<!DOCTYPE html>
<!-- saved from url=(0037)http://www.jianshu.com/p/c1a776c7a228 -->
<html><!--<![endif]--><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  
  <meta http-equiv="X-UA-Compatible" content="IE=Edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0,user-scalable=no">

  <!-- Start of Baidu Transcode -->
  <meta http-equiv="Cache-Control" content="no-siteapp">
  <meta http-equiv="Cache-Control" content="no-transform">
  <meta name="applicable-device" content="pc,mobile">
  <meta name="MobileOptimized" content="width">
  <meta name="HandheldFriendly" content="true">
  <meta name="mobile-agent" content="format=html5;url=http://www.jianshu.com/p/c1a776c7a228">
  <!-- End of Baidu Transcode -->

    <meta name="description" content="1.安装 可以简单地在页面引入Vue.js作为独立版本，Vue即被注册为全局变量，可以在页面使用了。 如果希望搭建大型应用，则可以使用npm安装Vue.js： 甚至可以使用vue官方推荐的项目模板来创建新的大型项目，这就需要使用vue命令行工具vue-cli： 2.概述 Vue的目标是实现响应的数据绑定和组合的视图组件，所以其核心只有两块： 数据绑定系统 组件系统 数据通过在HTML模板中的...">

  <meta name="360-site-verification" content="604a14b53c6b871206001285921e81d8">
  <meta property="wb:webmaster" content="294ec9de89e7fadb">
  <meta property="qc:admins" content="104102651453316562112116375">
  <meta property="qc:admins" content="11635613706305617">
  <meta property="qc:admins" content="1163561616621163056375">
  <meta name="google-site-verification" content="cV4-qkUJZR6gmFeajx_UyPe47GW9vY6cnCrYtCHYNh4">
  <meta name="google-site-verification" content="HF7lfF8YEGs1qtCE-kPml8Z469e2RHhGajy6JPVy5XI">
  <meta http-equiv="mobile-agent" content="format=html5; url=http://www.jianshu.com/p/c1a776c7a228">

  <!-- Apple -->
  <meta name="apple-mobile-web-app-title" content="简书">

    <!--  Meta for Smart App Banner -->
  <meta name="apple-itunes-app" content="app-id=888237539, app-argument=jianshu://notes/5917355">
  <!-- End -->

  <!--  Meta for Twitter Card -->
  <meta content="summary" property="twitter:card">
  <meta content="@jianshucom" property="twitter:site">
  <meta content="Vue官方教程笔记（Vue 1.X）" property="twitter:title">
  <meta content="1.安装 可以简单地在页面引入Vue.js作为独立版本，Vue即被注册为全局变量，可以在页面使用了。 如果希望搭建大型应用，则可以使用npm安装Vue.js： 甚至可以使用vue官方推荐的项目模板来创建新的大型项目，这就需要使用vue命令行工具vue-cli： 2.概述 Vue的目标是实现响应的数据绑定和组合的视图组件，所以其核心只有两块： 数据绑定系统 组件系统 数据通过在HTML模板中的指令和“Mustache”语法，绑定到对应的HTML元素上，其底层是JavaScript对象的存取器属性和原生javascript事件。 组件系统则通过扩展的Vue实例，来渲染位于HTML中的类似于自..." property="twitter:description">
  <meta content="http://www.jianshu.com/p/c1a776c7a228" property="twitter:url">
  <!-- End -->

  <!--  Meta for OpenGraph -->
  <meta property="fb:app_id" content="865829053512461">
  <meta property="og:site_name" content="简书">
  <meta property="og:title" content="Vue官方教程笔记（Vue 1.X）">
  <meta property="og:type" content="article">
  <meta property="og:url" content="http://www.jianshu.com/p/c1a776c7a228">
  <meta property="og:description" content="1.安装 可以简单地在页面引入Vue.js作为独立版本，Vue即被注册为全局变量，可以在页面使用了。 如果希望搭建大型应用，则可以使用npm安装Vue.js： 甚至可以使用vue官方推荐的项目模...">
  <!-- End -->

  <!--  Meta for Facebook Applinks -->
  <meta property="al:ios:url" content="jianshu://notes/5917355">
  <meta property="al:ios:app_store_id" content="888237539">
  <meta property="al:ios:app_name" content="简书">

  <meta property="al:android:url" content="jianshu://notes/5917355">
  <meta property="al:android:package" content="com.jianshu.haruki">
  <meta property="al:android:app_name" content="简书">
  <!-- End -->


    <title>Vue官方教程笔记（Vue 1.X） - 简书</title>

  <meta name="csrf-param" content="authenticity_token">
<meta name="csrf-token" content="NqLhN1+2KjSzaNGDltJP37m3nIg9cnC5m6rgS+2OisUb5jR/CiNG295BCKb1aYTccEdQ4zvhc7kMhbOPqxQT7Q==">

  <link rel="stylesheet" media="all" href="./Vue官方教程笔记（Vue 1.X） - 简书_files/web-096a5331e66d587e2ffe.css">
  
  <link rel="stylesheet" media="all" href="./Vue官方教程笔记（Vue 1.X） - 简书_files/entry-85bfb5240b553cc70591.css">

  <link href="http://cdn2.jianshu.io/assets/favicons/favicon-03411b154a430b85d807b4366489c21122fb983a38f3d7ca926f882e6367b13e.ico" rel="icon">
      <link rel="apple-touch-icon-precomposed" href="http://cdn2.jianshu.io/assets/apple-touch-icons/57-a6f1f1ee62ace44f6dc2f6a08575abd3c3b163288881c78dd8d75247682a4b27.png" sizes="57x57">
      <link rel="apple-touch-icon-precomposed" href="http://cdn2.jianshu.io/assets/apple-touch-icons/72-fb9834bcfce738fd7b9c5e31363e79443e09a81a8e931170b58bc815387c1562.png" sizes="72x72">
      <link rel="apple-touch-icon-precomposed" href="http://cdn2.jianshu.io/assets/apple-touch-icons/76-49d88e539ff2489475d603994988d871219141ecaa0b1a7a9a1914f4fe3182d6.png" sizes="76x76">
      <link rel="apple-touch-icon-precomposed" href="http://cdn2.jianshu.io/assets/apple-touch-icons/114-24252fe693524ed3a9d0905e49bff3cbd0228f25a320aa09053c2ebb4955de97.png" sizes="114x114">
      <link rel="apple-touch-icon-precomposed" href="http://cdn2.jianshu.io/assets/apple-touch-icons/120-1bb7371f5e87f93ce780a5f1a05ff1b176828ee0d1d130e768575918a2e05834.png" sizes="120x120">
      <link rel="apple-touch-icon-precomposed" href="http://cdn2.jianshu.io/assets/apple-touch-icons/152-bf209460fc1c17bfd3e2b84c8e758bc11ca3e570fd411c3bbd84149b97453b99.png" sizes="152x152">

  <!-- Start of 访问统计 -->
  <script src="./Vue官方教程笔记（Vue 1.X） - 简书_files/push.js.下载"></script><script src="./Vue官方教程笔记（Vue 1.X） - 简书_files/hm.js.下载"></script><script async="" src="./Vue官方教程笔记（Vue 1.X） - 简书_files/analytics.js.下载"></script><script>
  (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
  })(window,document,'script','https://www.google-analytics.com/analytics.js','ga');

  ga('create', 'UA-35169517-1', 'auto');
  ga('send', 'pageview');
</script><style type="text/css" abt="234"></style>

<script>
  var _hmt = _hmt || [];
  (function() {
    var hm = document.createElement("script");
    hm.src = "//hm.baidu.com/hm.js?0c0e9d9b1e7d617b3e6842e85b9fb068";
    var s = document.getElementsByTagName("script")[0];
    s.parentNode.insertBefore(hm, s);
  })();
</script>

  <!-- End of 访问统计 -->
<style type="text/css">
@charset "UTF-8";
/*
 * 变量
*/
.main {
  position: relative;
  margin: 0 auto;
  padding: 0 0 30px 0;
  width: 620px;
}
.main .title {
    padding-left: 8px;
    border-left: 3px solid #EA6F5A;
    line-height: 1;
    font-size: 15px;
}
.main .collection-settings {
    position: absolute;
    top: 2px;
    right: 0;
    font-size: 13px;
    color: #A0A0A0;
}
.main .collection-settings span {
      padding-left: 4px;
}
.main .include-collection {
    width: 100%;
    padding-top: 20px;
    display: -webkit-box;
    display: -webkit-flex;
    display: -ms-flexbox;
    display: flex;
    -webkit-box-orient: horizontal;
    -webkit-box-direction: normal;
    -webkit-flex-direction: row;
        -ms-flex-direction: row;
            flex-direction: row;
    -webkit-box-pack: start;
    -webkit-justify-content: flex-start;
        -ms-flex-pack: start;
            justify-content: flex-start;
    -webkit-box-align: center;
    -webkit-align-items: center;
        -ms-flex-align: center;
            align-items: center;
    -webkit-flex-wrap: wrap;
        -ms-flex-wrap: wrap;
            flex-wrap: wrap;
}
.main .include-collection .item {
      display: inline-block;
      margin: 0 12px 12px 0;
      min-height: 32px;
      background-color: white;
      border: 1px solid #DCDCDC;
      border-radius: 4px;
      vertical-align: top;
      overflow: hidden;
}
.main .include-collection .item img {
        width: 32px;
        height: 32px;
}
.main .include-collection .item .name {
        display: inline-block;
        padding: 0 10px;
        font-size: 14px;
}
.main .include-collection .add-collection-wrap {
      margin: 0 12px 12px 0;
}
.main .include-collection .add-collection {
      padding: 8px 12px;
      font-size: 14px;
      border: 1px solid #DCDCDC;
      border-radius: 4px;
}
.main .include-collection .add-collection i {
        margin-right: 4px;
        color: #969696;
}
.main .recommend-note a {
    position: relative;
    margin: 20px 2px 0 0;
    width: 200px;
    height: 160px;
    display: inline-block;
}
.main .recommend-note a:after {
      content: "";
      position: absolute;
      width: 200px;
      height: 160px;
      border-radius: 0 0 4px 4px;
      -webkit-box-shadow: inset 0px -80px 50px -22px rgba(0, 0, 0, 0.6);
              box-shadow: inset 0px -80px 50px -22px rgba(0, 0, 0, 0.6);
      top: 0;
      left: 0;
      z-index: 1;
}
.main .recommend-note .name {
    position: absolute;
    bottom: 40px;
    left: 10px;
    right: 10px;
    font-size: 17px;
    font-weight: bold;
    color: #ffffff;
    z-index: 2;
}
.main .recommend-note .author {
    position: absolute;
    bottom: 10px;
    left: 10px;
    right: 10px;
    z-index: 2;
}
.main .recommend-note .avatar {
    width: 20px;
    height: 20px;
    display: inline-block;
}
.main .recommend-note .avatar img {
      border-radius: 50%;
}
.main .recommend-note .author-name {
    font-size: 12px;
    color: #ffffff;
    display: inline-block;
    vertical-align: -1px;
}
.main .show-more {
    margin: 0 12px 12px 0;
    font-size: 14px;
    color: #A0A0A0;
}
</style><script>//console.log('a')
</script><script>doAdblock();
function doAdblock(){
    (function() {
        function A() {}
        A.prototype = {
            rules: {
                'pps_pps': {
                    'find': /^http:\/\/www\.iqiyi\.com\/player\/cupid\/common\/pps_flvplay_s\.swf/,
                    'replace': 'http://swf.adtchrome.com/pps_20140420.swf'
                },
                '17173_in':{
                    'find':/http:\/\/f\.v\.17173cdn\.com\/(\d+\/)?flash\/PreloaderFile(Customer)?\.swf/,
                    'replace':"http://swf.adtchrome.com/17173_in_20150522.swf"
                },
                '17173_out':{
                    'find':/http:\/\/f\.v\.17173cdn\.com\/(\d+\/)?flash\/PreloaderFileFirstpage\.swf/,
                    'replace':"http://swf.adtchrome.com/17173_out_20150522.swf"
                },
                '17173_live':{
                    'find':/http:\/\/f\.v\.17173cdn\.com\/(\d+\/)?flash\/Player_stream(_firstpage)?\.swf/,
                    'replace':"http://swf.adtchrome.com/17173_stream_20150522.swf"
                },
                '17173_live_out':{
                    'find':/http:\/\/f\.v\.17173cdn\.com\/(\d+\/)?flash\/Player_stream_(custom)?Out\.swf/,
                    'replace':"http://swf.adtchrome.com/17173.out.Live.swf"
                }
            },
            _done: null,
            get done() {
                if(!this._done) {
                    this._done = new Array();
                }
                return this._done;
            },
            addAnimations: function() {
                var style = document.createElement('style');
                style.type = 'text/css';
                style.innerHTML = 'object,embed{\
                -webkit-animation-duration:.001s;-webkit-animation-name:playerInserted;\
                -ms-animation-duration:.001s;-ms-animation-name:playerInserted;\
                -o-animation-duration:.001s;-o-animation-name:playerInserted;\
                animation-duration:.001s;animation-name:playerInserted;}\
                @-webkit-keyframes playerInserted{from{opacity:0.99;}to{opacity:1;}}\
                @-ms-keyframes playerInserted{from{opacity:0.99;}to{opacity:1;}}\
                @-o-keyframes playerInserted{from{opacity:0.99;}to{opacity:1;}}\
                @keyframes playerInserted{from{opacity:0.99;}to{opacity:1;}}';
                document.getElementsByTagName('head')[0].appendChild(style);
            },
            animationsHandler: function(e) {
                if(e.animationName === 'playerInserted') {
                    this.replace(e.target);
                }
            },
            replace: function(elem) {
                if (/http:\/\/v.youku.com\/v_show\/.*/.test(window.location.href)){
                    var tag = document.getElementById("playerBox").getAttribute("player")
                    if (tag == "adt"){
                        console.log("adt adv")
                        return;
                    }
                }
                if(this.done.indexOf(elem) != -1) return;
                this.done.push(elem);
                var player = elem.data || elem.src;
                if(!player) return;
                var i, find, replace = false;
                for(i in this.rules) {
                    find = this.rules[i]['find'];
                    if(find.test(player)) {
                        replace = this.rules[i]['replace'];
                        if('function' === typeof this.rules[i]['preHandle']) {
                            this.rules[i]['preHandle'].bind(this, elem, find, replace, player)();
                        }else{
                            this.reallyReplace.bind(this, elem, find, replace)();
                        }
                        break;
                    }
                }
            },
            reallyReplace: function(elem, find, replace) {
                elem.data && (elem.data = elem.data.replace(find, replace)) || elem.src && ((elem.src = elem.src.replace(find, replace)) && (elem.style.display = 'block'));
                var b = elem.querySelector("param[name='movie']");
                this.reloadPlugin(elem);
            },
            reloadPlugin: function(elem) {
                var nextSibling = elem.nextSibling;
                var parentNode = elem.parentNode;
                parentNode.removeChild(elem);
                var newElem = elem.cloneNode(true);
                this.done.push(newElem);
                if(nextSibling) {
                    parentNode.insertBefore(newElem, nextSibling);
                } else {
                    parentNode.appendChild(newElem);
                }
            },
            init: function() {
                var handler = this.animationsHandler.bind(this);
                document.body.addEventListener('webkitAnimationStart', handler, false);
                document.body.addEventListener('msAnimationStart', handler, false);
                document.body.addEventListener('oAnimationStart', handler, false);
                document.body.addEventListener('animationstart', handler, false);
                this.addAnimations();
            }
        };
        new A().init();
    })();
}
// 20140730
(function cnbeta() {
    if (document.URL.indexOf('cnbeta.com') >= 0) {
        var elms = document.body.querySelectorAll("p>embed");
        Array.prototype.forEach.call(elms, function(elm) {
            elm.style.marginLeft = "0px";
        });
    }
})();
//baidu
if(document.URL.indexOf('www.baidu.com') >= 0){
    if(document && document.getElementsByTagName && document.getElementById && document.body){
        var aa = function(){
            var all = document.body.querySelectorAll("#content_left div,#content_left table");
            for(var i = 0; i < all.length; i++){
                if(/display:\s?(table|block)\s!important/.test(all[i].getAttribute("style"))){all[i].style.display= "none";all[i].style.visibility='hidden';}
            }
            all = document.body.querySelectorAll('.result.c-container[id="1"]');
            //if(all.length == 1) return;
            for(var i = 0; i < all.length; i++){
                if(all[i].innerHTML && all[i].innerHTML.indexOf('广告')>-1){
                    all[i].style.display= "none";all[i].style.visibility='hidden';
                }
            }
        }
        aa();
        document.getElementById('wrapper_wrapper').addEventListener('DOMSubtreeModified',aa)
    };
}
// 20140922
(function kill_360() {
    if (document.URL.indexOf('so.com') >= 0) {
        document.getElementById("e_idea_pp").style.display = none;
    }
})();
if (document.URL.indexOf("tv.sohu.com") >= 0){
    if (document.cookie.indexOf("fee_status=true")==-1){document.cookie='fee_status=true'};
}
if (document.URL.indexOf("56.com") >= 0){
    if (document.cookie.indexOf("fee_status=true")==-1){document.cookie='fee_status=true'};
}
if (document.URL.indexOf("iqiyi.com") >= 0){
    if (document.cookie.indexOf("player_forcedType=h5_VOD")==-1){
        document.cookie='player_forcedType=h5_VOD'
        if(localStorage.reloadTime && Date.now() - parseInt(localStorage.reloadTime)<60000){
            console.log('no reload')
        }else{
            location.reload()
            localStorage.reloadTime = Date.now();
        }
    }
}
</script><style type="text/css">object,embed{                -webkit-animation-duration:.001s;-webkit-animation-name:playerInserted;                -ms-animation-duration:.001s;-ms-animation-name:playerInserted;                -o-animation-duration:.001s;-o-animation-name:playerInserted;                animation-duration:.001s;animation-name:playerInserted;}                @-webkit-keyframes playerInserted{from{opacity:0.99;}to{opacity:1;}}                @-ms-keyframes playerInserted{from{opacity:0.99;}to{opacity:1;}}                @-o-keyframes playerInserted{from{opacity:0.99;}to{opacity:1;}}                @keyframes playerInserted{from{opacity:0.99;}to{opacity:1;}}</style></head>

  <body lang="zh-CN" class="reader-black-font">
    <!-- 全局顶部导航栏 -->
<nav class="navbar navbar-default navbar-fixed-top" role="navigation">
  <div class="width-limit">
    <!-- 左上方 Logo -->
    <a class="logo" href="http://www.jianshu.com/"><img src="./Vue官方教程笔记（Vue 1.X） - 简书_files/logo-58fd04f6f0de908401aa561cda6a0688.png" alt="Logo"></a>

    <!-- 右上角 -->
      <!-- 登录显示写文章 -->
      <a class="btn write-btn" target="_blank" href="http://www.jianshu.com/writer#/">
        <i class="iconfont ic-write"></i>写文章
</a>
    <!-- 如果用户登录，显示下拉菜单 -->
      <div class="user">
        <div data-hover="dropdown">
          <a class="avatar" href="http://www.jianshu.com/u/aae7e00037b6"><img src="./Vue官方教程笔记（Vue 1.X） - 简书_files/b7b003ddd980.jpg" alt="120"></a>
        </div>
        <ul class="dropdown-menu">
          <li>
            <a href="http://www.jianshu.com/u/aae7e00037b6">
              <i class="iconfont ic-navigation-profile"></i><span>我的主页</span>
</a>          </li>
          <li>
            <!-- TODO bookmarks_path -->
            <a href="http://www.jianshu.com/bookmarks">
              <i class="iconfont ic-navigation-mark"></i><span>收藏的文章</span>
</a>          </li>
          <li>
            <a href="http://www.jianshu.com/users/aae7e00037b6/liked_notes">
              <i class="iconfont ic-navigation-like"></i><span>喜欢的文章</span>
</a>          </li>
          <li>
            <a href="http://www.jianshu.com/wallet">
              <i class="iconfont ic-navigation-wallet"></i><span>我的钱包</span>
</a>          </li>
          <li>
            <a href="http://www.jianshu.com/settings">
              <i class="iconfont ic-navigation-settings"></i><span>设置</span>
</a>          </li>
          <li>
            <a href="http://www.jianshu.com/faqs">
              <i class="iconfont ic-navigation-feedback"></i><span>帮助与反馈</span>
</a>          </li>
          <li>
            <a rel="nofollow" data-method="delete" href="http://www.jianshu.com/sign_out">
              <i class="iconfont ic-navigation-signout"></i><span>退出</span>
</a>          </li>
        </ul>
      </div>

    <div class="style-mode"><a class="style-mode-btn"><i class="iconfont ic-navigation-mode"></i></a> <div class="popover-modal" style="left: 0px; display: none;"><div class="meta"><i class="iconfont ic-navigation-night"></i><span>夜间模式</span></div> <div class="switch day-night-group"><a class="switch-btn">开</a> <a class="switch-btn active">关</a></div> <hr> <div class="switch font-family-group"><a class="switch-btn font-song">宋体</a> <a class="switch-btn font-hei active">黑体</a></div> <div class="switch"><a class="switch-btn active">简</a> <a class="switch-btn">繁</a></div></div></div>
    <div class="container">
      <div class="navbar-header">
        <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#menu" aria-expanded="false">
          <span class="icon-bar"></span>
          <span class="icon-bar"></span>
          <span class="icon-bar"></span>
        </button>
      </div>
      <div class="collapse navbar-collapse" id="menu">
        <ul class="nav navbar-nav">
            <li class="">
              <a href="http://www.jianshu.com/">
                <span class="menu-text">发现</span><i class="iconfont ic-navigation-discover menu-icon"></i>
</a>            </li>
            <li class="">
              <a href="http://www.jianshu.com/subscriptions">
                <span class="menu-text">关注</span><i class="iconfont ic-navigation-follow menu-icon"></i>
</a>            </li>
            <li class="notification"><a data-hover="dropdown" href="http://www.jianshu.com/notifications" class="notification-btn"><span class="menu-text">消息</span> <i class="iconfont ic-navigation-notification menu-icon"></i> <!----> <!----></a> <ul class="dropdown-menu"><li><a href="http://www.jianshu.com/notifications#/comments"><i class="iconfont ic-comments"></i> <span>评论</span> <!----></a></li><li><a href="http://www.jianshu.com/notifications#/chats"><i class="iconfont ic-chats"></i> <span>简信</span> <!----></a></li><li><a href="http://www.jianshu.com/notifications#/requests"><i class="iconfont ic-requests"></i> <span>投稿请求</span> <!----></a></li><li><a href="http://www.jianshu.com/notifications#/likes"><i class="iconfont ic-likes"></i> <span>喜欢和赞</span> <!----></a></li><li><a href="http://www.jianshu.com/notifications#/follows"><i class="iconfont ic-follows"></i> <span>关注</span> <!----></a></li><li><a href="http://www.jianshu.com/notifications#/money"><i class="iconfont ic-money"></i> <span>赞赏</span> <!----></a></li><li><a href="http://www.jianshu.com/notifications#/others"><i class="iconfont ic-others"></i> <span>其他消息</span> <!----></a></li></ul></li>
          <li class="search">
            <form target="_blank" action="http://www.jianshu.com/search" accept-charset="UTF-8" method="get"><input name="utf8" type="hidden" value="✓">
              <input type="text" name="q" id="q" value="" autocomplete="off" placeholder="搜索" class="search-input">
              <a class="search-btn" href="javascript:void(null)"><i class="iconfont ic-search"></i></a>
</form>          </li>
        </ul>
      </div>
    </div>
  </div>
</nav>

    
<div class="note">
  <a target="_blank" href="http://www.jianshu.com/apps/download?utm_source=sbc" id="web-note-ad-fixed"><span class="close">×</span></a>
  <div class="post">
    <div class="article">
        <h1 class="title">Vue官方教程笔记（Vue 1.X）</h1>

        <!-- 作者区域 -->
        <div class="author">
          <a class="avatar" href="http://www.jianshu.com/u/3c8fe1455914">
            <img src="./Vue官方教程笔记（Vue 1.X） - 简书_files/a7744da1-649b-4db5-8e59-97e5b3d17de9.jpg" alt="96">
</a>          <div class="info">
            <span class="name"><a href="http://www.jianshu.com/u/3c8fe1455914">Awey</a></span>
            <!-- 关注用户按钮 -->
            <a class="btn btn-success follow"><i class="iconfont ic-follow"></i><span>关注</span></a>
            <!-- 文章数据信息 -->
            <div class="meta">
              <!-- 如果文章更新时间大于发布时间，那么使用 tooltip 显示更新时间 -->
                <span class="publish-time" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="最后编辑于 2017.01.10 09:14">2016.09.21 18:00*</span>
              <span class="wordage">字数 9633</span>
            <span class="views-count">阅读 4210</span><span class="comments-count">评论 3</span><span class="likes-count">喜欢 102</span></div>
          </div>
          <!-- 如果是当前作者，加入编辑按钮 -->
        </div>
        <!-- -->

        <!-- 文章内容 -->
        <div data-note-content="" class="show-content">
          <h3>1.安装</h3>
<p>可以简单地在页面引入Vue.js作为独立版本，Vue即被注册为全局变量，可以在页面使用了。</p>
<p>如果希望搭建大型应用，则可以使用npm安装Vue.js：</p>
<pre class="hljs undefined"><code># 最新稳定版本
$ npm install vue
# 最新稳定 CSP 兼容版本
$ npm install vue@csp</code></pre>
<p>甚至可以使用vue官方推荐的项目模板来创建新的大型项目，这就需要使用vue命令行工具vue-cli：</p>
<pre class="hljs undefined"><code># 全局安装 vue-cli
$ npm install -g vue-cli
# 创建一个基于 "webpack" 模板的新项目
$ vue init webpack my-project
# 安装依赖，走你
$ cd my-project
$ npm install
$ npm run dev</code></pre>
<h3>2.概述</h3>
<p>Vue的目标是实现响应的数据绑定和组合的视图组件，所以其核心只有两块：</p>
<ul>
<li>数据绑定系统</li>
<li>组件系统</li>
</ul>
<p>数据通过在HTML模板中的指令和“Mustache”语法，绑定到对应的HTML元素上，其底层是JavaScript对象的存取器属性和原生javascript事件。</p>
<p>组件系统则通过扩展的Vue实例，来渲染位于HTML中的类似于自定义元素的Vue组件，从而实现独立可复用的组件。</p>
<h3>3.Vue实例</h3>
<p>每个Vue应用的起步都是从一个Vue的根实例开始：</p>
<pre class="hljs javascript"><code class="javascript"><span class="hljs-keyword">var</span> vm = <span class="hljs-keyword">new</span> Vue({
    <span class="hljs-comment">//选项，包含数据、模板、挂载元素等</span>
})</code></pre>
<p>而每个组件，也是一个扩展的vue实例：</p>
<pre class="hljs javascript"><code class="javascript"><span class="hljs-keyword">var</span> myCompnent = Vue.extend({
    <span class="hljs-comment">//选项，包含组件的数据、模板、挂载元素等</span>
})</code></pre>
<p>Vue实例会代理设置在<code>data</code>选项中的数据，所有<code>data</code>选项中的数据都可以通过vm本身进行访问：</p>
<pre class="hljs javascript"><code class="javascript"><span class="hljs-keyword">var</span> vm = <span class="hljs-keyword">new</span> Vue({
    <span class="hljs-attr">data</span>: {
        <span class="hljs-attr">name</span>: <span class="hljs-string">'chen'</span>
    }
})
data.name  <span class="hljs-comment">// -&gt; chen</span>
vm.name = <span class="hljs-string">'wei'</span>
data.name <span class="hljs-comment">// -&gt; wei</span></code></pre>
<p>除了数据属性，Vue实例还暴露了一些有用的实例属性与方法，这些属性与方法都有前缀$，区别于数据属性（参考API文档）：</p>
<pre class="hljs javascript"><code class="javascript">vm.$watch
vm.$data
vm.$el</code></pre>
<p>在一个Vue实例的生命周期的不同时间，可以调用相应的回调函数：<br></p><div class="image-package">
<img src="./Vue官方教程笔记（Vue 1.X） - 简书_files/3094907-926e74e9cd2ae05c.png" data-original-src="http://upload-images.jianshu.io/upload_images/3094907-926e74e9cd2ae05c.png?imageMogr2/auto-orient/strip%7CimageView2/2" style="cursor: zoom-in;"><br><div class="image-caption">实例生命周期</div>
</div>
<h3>4.数据绑定</h3>
<p>有两种方式可以进行数据绑定：插值和指令。</p>
<h4>4.1 插值</h4>
<p>使用双大括号语法来绑定数据到HTML中，使用三大括号语法来输出HTML字符（不常用）。插值也可以用在HTML属性中：</p>
<pre class="hljs undefined"><code class="html">&lt;span&gt; {{msg }}&lt;/span&gt;
&lt;div&gt;{{{ raw_html }}}&lt;/div&gt;
&lt;div id="item-{{ id }}"&gt;&lt;/div&gt;</code></pre>
<h4>4.2 指令</h4>
<p>使用指令 (Directives，是特殊的带有前缀<code>v-</code>的特性）来将数据绑定到HTML，通常用于应用特殊行为到DOM上：</p>
<pre class="hljs undefined"><code class="html">&lt;p v-if="greeting"&gt;Hello!&lt;/p&gt;   &lt;!--当greeting为真时p存在--&gt;</code></pre>
<p>指令有三个需要记住的特征：</p>
<ul>
<li>参数：<code>v-on:click="doSomething"</code> ，这里<code>click</code>是<code>v-on</code>指令的参数</li>
<li>修饰符：<code>v-on:click.stop="doSomething"</code>，这里<code>.stop</code>是修饰符，表示阻止冒泡</li>
<li>缩写：<code>v-bind</code>指令可缩写为简单的<code>:</code>号，<code>v-on</code>指令可以缩写为<code>@</code>号<pre class="hljs undefined"><code class="html">&lt;a :href="url"&gt;&lt;/a&gt;
&lt;a @click="doSomething"&gt;&lt;/a&gt;</code></pre>
</li>
</ul>
<p>插值的内容和指令的值，都被限定为只能使用绑定表达式，它由一个JavaScript表达式和可选的一个或多个过滤器构成。需要注意JavaScript表达式和语句的区别，而过滤器则是一个JavaScript函数，Vue提供了很多内置的过滤器，也可以自己编写自定义过滤器：</p>
<pre class="hljs undefined"><code>{{ message | filterA | filterB }}
{{ message | filterA 'arg1' arg2 }} // 过滤器也可以接受参数</code></pre>
<h3>5.计算属性</h3>
<p>绑定表达式被限定只能使用一个JavaScript表达式，目的是为了限制在数据绑定中放入过多的逻辑。如果需要更复杂的数据处理逻辑，则应该使用计算属性：</p>
<pre class="hljs javascript"><code class="javascript"><span class="hljs-keyword">var</span> vm = <span class="hljs-keyword">new</span> Vue({
  <span class="hljs-attr">el</span>: <span class="hljs-string">'#example'</span>,
    <span class="hljs-attr">data</span>: {
      <span class="hljs-attr">a</span>: <span class="hljs-number">1</span>
    },
    <span class="hljs-attr">conmpued</span>: {
      a () {
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.a+<span class="hljs-number">1</span>
      }
    }
})</code></pre>
<h4>5.1 getter和setter</h4>
<p>Vue默认将提供的回调函数作为计算属性的getter来使用，所以默认计算属性是只读的。但是必要时也可指定计算属性的setter：</p>
<pre class="hljs javascript"><code class="javascript">computed: {
  <span class="hljs-attr">fullName</span>: {
    <span class="hljs-comment">// getter</span>
    get: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
      <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.firstName + <span class="hljs-string">' '</span> + <span class="hljs-keyword">this</span>.lastName
    },
    <span class="hljs-comment">// setter</span>
    set: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">newValue</span>) </span>{
      <span class="hljs-keyword">var</span> names = newValue.split(<span class="hljs-string">' '</span>)
      <span class="hljs-keyword">this</span>.firstName = names[<span class="hljs-number">0</span>]
      <span class="hljs-keyword">this</span>.lastName = names[names.length - <span class="hljs-number">1</span>]
    }
  }
}</code></pre>
<h4>5.2 $watch</h4>
<p>Vue还提供了一个$watch方法用于监视数据变动：</p>
<pre class="hljs javascript"><code class="javascript">vm.$watch(<span class="hljs-string">'a'</span>, val =&gt; {
  <span class="hljs-built_in">console</span>.log(val)
})
<span class="hljs-comment">// 或者写成：</span>
<span class="hljs-keyword">var</span> vm = <span class="hljs-keyword">new</span> Vue({
  … …
  watch: {
    <span class="hljs-string">'a'</span> (val) { <span class="hljs-comment">// 以需要监测的属性为属性名</span>
      <span class="hljs-built_in">console</span>.log(val)
    }
  }
})</code></pre>
<p>但是因为可读性，推荐使用计算属性而不是watch方法。</p>
<h3>6.Class与Style绑定</h3>
<p>由于其常用性，Vue增强了<code>class</code>与<code>style</code>两个HTML属性的绑定，不仅仅可以接受字符串值，还可以接受数组和对象两种类型的值。</p>
<h4>6.1 class绑定</h4>
<p><code>v-bind:class="value"</code>，接受字符串，也可以接受对象和数组，并且还可以和普通的<code>class</code>属性共存：</p>
<pre class="hljs undefined"><code class="html">&lt;!-- 接受字符串 --&gt;
v-bind:class="classA"
&lt;!-- 接受对象 --&gt;
v-bind:class="{ 'class-a': isA, 'class-b': isB }"
&lt;!-- 直接绑定数据里的对象，或者计算属性返回的对象 --&gt;
v-bind:class="classObject"
&lt;!-- 与普通class属性共存 --&gt;
class="some-class" v-bind:class="{ 'class-a': isA, 'class-b': isB }"
&lt;!-- 接受数组 --&gt;
v-bind:class="[classA, classB]"
&lt;!--直接绑定数据里的数组，或者计算属性返回的数组 --&gt;
v-bind:class="classArray"
&lt;!--数组语法与对象语法混用  1.0.19+ --&gt;
v-bind:class="[classA, { 'class-b': isB, 'class-c': isC}]"</code></pre>
<h4>6.2 style绑定</h4>
<p>内联样式绑定也可以接受对象或者数组，当接受对象时语法非常直观（看着非常像CSS语法），当接受数组时可以将多个样式对象应用到元素上。对象和数组都可以直接来自数据<code>data</code>或者<code>computed</code>或者<code>props</code>。</p>
<p>同时内联样式的绑定Vue会自动侦测浏览器并添加相应浏览器前缀。</p>
<pre class="hljs undefined"><code class="html">&lt;!-- 接受对象 --&gt;
v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }"
&lt;!-- 直接绑定数据里的对象，或者计算属性返回的对象 --&gt;
v-bind:style="styleObject"

v-bind:style="[styleObjectA, styleObjectB]"</code></pre>
<h3>7.条件渲染</h3>
<p>Vue可以根据指定的条件来决定是否渲染元素，有两个指令<code>v-if</code>和<code>v-show</code>，用法基本一致。</p>
<h4>7.1 条件渲染一个元素</h4>
<pre class="hljs undefined"><code class="html">&lt;h1 v-if="isOk"&gt;Hello&lt;/h1&gt;</code></pre>
<h4>7.2 条件渲染多个元素</h4>
<p>使用一个<code>template</code> 元素包裹多个元素并条件渲染它。</p>
<pre class="hljs undefined"><code class="html">&lt;template v-if="isOk"&gt;
  &lt;h1&gt;Title&lt;/h1&gt;
  &lt;p&gt;Paragraph 1&lt;/p&gt;
  &lt;p&gt;Paragraph 2&lt;/p&gt;
&lt;/template &gt;</code></pre>
<h4>7.3 v-else</h4>
<p>还可以使用<code>v-else</code>来为条件渲染添加一个<code>else</code>块：</p>
<pre class="hljs undefined"><code class="html">&lt;div v-if="isOk"&gt;hello&lt;/div&gt;
&lt;!-- v-else指令必须紧跟v-if或v-show否则不生效 --&gt;
&lt;div v-else&gt;fuck off&lt;/div&gt;
&lt;!-- 这两个元素仅会显示一个 --&gt;</code></pre>
<h4>7.4 组件中的条件渲染</h4>
<p>组件也可使用条件渲染，但是将v-show用在组件中时，由于指令的优先级问题，不能在后面使用v-else指令，而应该使用另一个v-show来替代：</p>
<pre class="hljs undefined"><code class="html">&lt;my-compnent v-show="condition"&gt;&lt;/my-component&gt;
&lt;p v-else&gt;这可能也是一个组件&lt;/p&gt; &lt;!--错误用法--&gt;

&lt;my-compnent v-show="condition"&gt;&lt;/my-component&gt;
&lt;p v-show="!condition"&gt;这可能也是一个组件&lt;/p&gt; &lt;!--正确用法--&gt;</code></pre>
<h4>7.5 v-if和v-show的区别</h4>
<p><strong>编译区别</strong>：<code>v-if</code>是惰性的，如果初始条件为假则这个元素不会被编译，只有当条件第一次为真时，Vue才编译并缓存编译结果以供后续使用；<code>v-show</code>的元素则直接编译。</p>
<p><strong>显示区别</strong>：<code>v-if</code>是真实的在HTML中重建或者销毁这个元素，<code>v-show</code>则只是通过<code>display</code>来控制，简单得多。</p>
<p><strong>结论</strong>：<code>v-if</code>有更高的切换消耗而<code>v-show</code>有更高的初始渲染消耗，频繁切换用<code>v-show</code>，条件稳定用<code>v-if</code></p>
<h3>8.列表渲染</h3>
<p>使用v-for指令，Vue可以根据一个数组，渲染一组列表元素。</p>
<h4>8.1 数组渲染</h4>
<pre class="hljs undefined"><code class="html">&lt;li v-for="item in items"&gt;{{ item.message + "：" + $index }}&lt;/li&gt;
&lt;!-- items是数据中的一个数组，item是数组元素的别名 --&gt;
&lt;!-- 有一个特殊变量：$index，是数组元素的索引 --&gt;</code></pre>
<h4>8.2 变异方法：</h4>
<p>Vue会更新被观察的数组items的大部分修改自身的方法：<code>push()</code>、<code>pop()</code>、<code>shift()</code>、<code>unshift()</code>、<code>splice()</code>、<code>sort()</code>、<code>reverse()</code>调用这些方法时数组的变动会被实时反映在数据绑定中，而那些不会修改原数组而是返回新数组的方法：<code>filter()</code>、<code>concat()</code>、<code>slice()</code>则需要使用其结果替换原数组，数据变动才能反映在数据绑定中。</p>
<h4>8.3 追踪指令：</h4>
<p>数组替换并不会完全重新渲染整个列表，Vue使用了一些启发算法提高了性能。默认这个算法是根据数组元素本身的值来追踪和复用DOM，这会导致数组中重复的值只会渲染一次，这时可以使用<code>track-by="$index"</code>指令强制Vue进入原位更新模式（只有<code>$index</code>位置的值与上次位置的值一致时才复用DOM元素，否则立刻重新生成并渲染新的DOM元素），但在需要同步临时状态和组件的私有状态时需谨慎使用。</p>
<p>如果数组中每个元素都有一个相同但值唯一的属性，比如下面这样</p>
<pre class="hljs javascript"><code class="javascript">{
  <span class="hljs-attr">items</span>: [
    { <span class="hljs-attr">_uid</span>: <span class="hljs-string">'88f869d'</span>, ... },
    { <span class="hljs-attr">_uid</span>: <span class="hljs-string">'7496c10'</span>, ... }
  ]
}</code></pre>
<p>则可以指定<code>track-by="_uid"</code>来让Vue尽可能地复用DOM以提高性能。</p>
<p>另外，如果数组元素是已经被<code>Object.freeze()</code>方法冻结的对象，则需要使用<code>track-by</code>指令明确指定追踪属性，否则将不能自动追踪（被冻结的对象无法设置存取器属性）</p>
<h4>8.4 检测盲点：</h4>
<p>由于JavaScript本身的限制，Vue不能检测到两种数据变动：</p>
<ol>
<li>直接使用索引赋值：<code>vm.items[0] = {}</code>
</li>
<li>修改数组的长度：<code>vm.items.length = 0</code>
</li>
</ol>
<p>应该使用下面两种技术进行替换：</p>
<ol>
<li>数组的Vue扩展方法：<pre class="hljs javascript"><code class="javascript"><span class="hljs-keyword">var</span> item = { <span class="hljs-attr">changeMsg</span>: <span class="hljs-string">'changed!'</span> }
vm.items.$set(<span class="hljs-number">0</span>, item)
vm.items.$remove(item)</code></pre>
</li>
<li>使用空数组替换：<code>vm.items = []</code>
</li>
</ol>
<h4>8.5 对象渲染</h4>
<p>遍历对象时可访问一个特殊变量<code>$key</code>，表示对象的键名</p>
<pre class="hljs undefined"><code class="html">&lt;ul&gt;
  &lt;li v-for="value in object"&gt; &lt;!-- value是对象键值的别名，object是数据对象的别名 --&gt;
    {{ $key }} : {{ value }}
  &lt;/li&gt;
&lt;/ul&gt;</code></pre>
<p>也可以给对象的键名提供一个别名</p>
<pre class="hljs undefined"><code class="html">&lt;ul&gt;
  &lt;li v-for="(key, value) in object"&gt; &lt;!-- value是对象键值的别名，object是数据对象的别名 --&gt;
    {{ key }} : {{ value }}
  &lt;/li&gt;
&lt;/ul&gt;</code></pre>
<p>对象遍历的结果是按Object.keys()的结果来的，不保证在所有引擎中都一致。</p>
<h4>8.6 值域渲染</h4>
<p>v-for也可以接受一个整数表示值域，即简单重复渲染元素：</p>
<pre class="hljs undefined"><code class="html">&lt;div&gt;
  &lt;span v-for="n in 10"&gt;{{ n }}&lt;/span&gt; /* 渲染10个span */
&lt;/div&gt;</code></pre>
<h4>8.7 渲染多个元素</h4>
<p>将v-for指令用在&lt;template&gt;&lt;/template&gt;元素上，可以重复渲染多个元素：</p>
<pre class="hljs undefined"><code class="html">&lt;ul&gt;
  &lt;template v-for="item in items"&gt;
    &lt;li&gt;{{ item.msg }}&lt;/li&gt;
    &lt;li class="divider"&gt;&lt;/li&gt;
  &lt;/template&gt;
&lt;/ul&gt;</code></pre>
<h4>8.8 过滤和排序</h4>
<p>有时我们想显示过滤/排序过的数组，同时不实际修改或重置原始数据。有两个办法：</p>
<ol>
<li>创建一个计算属性，返回过滤/排序过的数组；</li>
<li>使用内置的过滤器<code>filterBy</code>和<code>orderBy</code>
</li>
</ol>
<p>计算属性有更好的控制力，也更灵活，因为它是全功能 JavaScript；但是通常过滤器更方便。</p>
<h3>9.方法与事件处理器</h3>
<h4>9.1 用法</h4>
<p>使用<code>v-on</code>指令监听DOM事件，<code>v-on</code>后接冒号传入事件类型名称，指令的值为事件处理器，事件处理器只能指定为<code>methods</code>中的一个方法或者一个JavaScript语句（通常是方法调用语句，方便传值）：</p>
<pre class="hljs undefined"><code class="html">&lt;button v-on:click="sayHi"&gt;click me&lt;/button&gt;
&lt;button v-on:click="say('Hello!')"&gt;click me&lt;/button&gt;</code></pre>
<h4>9.2 事件对象</h4>
<p>事件处理器可以接受一个特殊参数即为事件对象，使用$event表示：</p>
<pre class="hljs undefined"><code class="html">&lt;button v-on:click="say('hello', $event)"&gt;click me&lt;/button&gt;</code></pre>
<h4>9.3 修饰符</h4>
<p><code>v-on</code>指令支持两类修饰符：事件修饰符和按键修饰符</p>
<p>事件修饰符有四个（1.0.16+）:</p>
<ul>
<li>prevent用于阻止默认事件（相当于event.preventDefault()）；</li>
<li>stop用于阻止冒泡（相当于event.stopPropagation()）；</li>
<li>capture表示添加侦听事件时使用捕获模式；</li>
<li>self表示只当事件是从侦听器绑定的元素本身触发时才触发回调。</li>
</ul>
<p>按键修饰符则表示只在指定按键上触发事件（通常在监听键盘事件时使用，<code>keyup</code>、<code>keydown</code>、<code>keypress</code>）</p>
<pre class="hljs undefined"><code class="html">&lt;input v-on:keyup.13="submit"&gt;</code></pre>
<p>除了使用keycode，按键修饰符还可以使用vue提供的按键别名：</p>
<p><code>enter</code>、<code>tab</code>、<code>delete</code>、<code>esc</code>、<code>space</code>、<code>up</code>、<code>down</code>、<code>left``right</code></p>
<p>1.0.8+可以使用单字母别名，所有26个字母都可以作为按键别名使用，1.0.17可以自定义按键别名：</p>
<pre class="hljs javascript"><code class="javascript">Vue.directive(<span class="hljs-string">'on'</span>).keyCodes.f1 = <span class="hljs-number">112</span></code></pre>
<h3>10.表单控件绑定</h3>
<h4>10.1 用法</h4>
<p>使用v-model指令在表单控件中创建双向数据绑定。</p>
<ol>
<li>文本输入框input中的输入与<code>model.text</code>的值实时双向同步<pre class="hljs undefined"><code class="html">&lt;input type="text" v-model="model.text" /&gt;</code></pre>
</li>
<li>单选按钮：选中则model.ratio的值为true，取消选中则model.ratio值变为false；反过来model.ratio值也改变选中状态<pre class="hljs undefined"><code class="html">&lt;input type="ratio" v-model="model.ratio" /&gt;</code></pre>
</li>
<li>多选框：单个多选框与单选框一样，多个多选框则需要绑定到一个数组上，并写好它们的value值以便填充到数组或从数组中删除<pre class="hljs undefined"><code class="html">&lt;input type="checkbox" value="jack" v-model="model.anArray" /&gt;
&lt;input type="checkbox" value="john" v-model="model.anArray" /&gt;
&lt;input type="checkbox" value="awey" v-model="model.anArray" /&gt;</code></pre>
</li>
<li>下拉框：单选的下拉框直接绑定即可，选中的选项的value或text也即该下拉框的value会与绑定的数据实时双向同步，多选的下拉框则需要绑定到一个数组上，选中的选项的value会添加到数组中。即使选项是v-for动态生成的，也不影响数据的双向绑定。<pre class="hljs undefined"><code class="html">&lt;select v-model="model.anArray" multiple&gt;
&lt;option selected&gt;A&lt;/option&gt;
&lt;option&gt;B&lt;/option&gt;
&lt;option&gt;C&lt;/option&gt;
&lt;/select&gt;</code></pre>
</li>
</ol>
<h4>10.2 绑定value</h4>
<p>所有表单控件都只能使用<code>v-model</code>而不能使用<code>v-bind:value</code>来进行数据双向绑定，因为<code>v-bind</code>指令在绑定普通属性（除了子组件的<code>prop</code>，它可以使用<code>async</code>修饰符）时，是数据到HTML的单向数据绑定，HTML中的变化是不会同步到数据中的。</p>
<p>但是如果希望<code>v-model</code>双向绑定的HTML和数据属性，指向的是vue实例中的另一个数据属性（比如有两个属性a和b，其中a绑定到v-mode上，b是另一个属性，如果希望radio和checkbox选中时，a的值为b，不选中时a的值为默认值），则可以使用<code>v-bind:value</code>来实现</p>
<ol>
<li>单选按钮：如果单选按钮选中，则isPicked指向anotherDataProperty（两个属性都是vue实例的data）<pre class="hljs undefined"><code class="html">&lt;input type="radio" v-model="isPicked" v-bind:value="anotherDataProperty"&gt;</code></pre>
</li>
<li>多选框：如果勾选则isSelected指向a，否则指向b，多选则是数组的元素指向a或b、<pre class="hljs undefined"><code class="html">&lt;input type="checkbox" v-model="isSelected" v-bind:true-value="a" v-bind:false-value="b"&gt;</code></pre>
</li>
<li>下拉框：如果选中a项，则selected的值指向a，多选则是数组的元素指向a<pre class="hljs undefined"><code class="html">&lt;select v-model="selected"&gt;
…
&lt;option v-bind:value="a"&gt;a&lt;/option&gt;
…
&lt;/select&gt;</code></pre>
</li>
</ol>
<p>在这种情况下使用v-bind:value指令，其值不限于字符串，可以是任意JavaScript值：</p>
<pre class="hljs undefined"><code class="html">&lt;input type="radio" v-model="isPicked" v-bind:value="{ name: awey, age: 26 }"&gt;</code></pre>
<h4>10.3 三个特性</h4>
<p>v-model可以使用三个特性，<code>lazy</code>、<code>debounce</code>和<code>number</code></p>
<ul>
<li>lazy：v-model在同步数据时使用的是input事件（可能是keyup事件，待考证）来进行同步，如果觉得太过频繁可使用lazy特性将同步改到change事件中<pre class="hljs undefined"><code class="html">&lt;input type="text" v-model="inputValue" lazy /&gt;</code></pre>
</li>
<li>debounce：设置一个最小延时，在每次敲击之后延时同步输入框的值与数据，（如果已经使用lazy则无效）<pre class="hljs undefined"><code class="html">&lt;input type="text" v-model="inputValue" debounce="500"/&gt;</code></pre>
</li>
<li>number：将用户输入的值转为number，不能转为Number类型则返回原值<pre class="hljs undefined"><code class="html">&lt;input type="text" v-model="inputValue" number /&gt;</code></pre>
<blockquote><p>表单控件有一些诸如<code>checked</code>和<code>disabled</code>这类HTML属性，无论赋值与否只要存在该属性即可生效。但是在使用<code>v-bind</code>绑定这类属性时，vue对其做了处理，值为真假值即可让属性生效或不生效，无需再有上述顾虑。</p></blockquote>
</li>
</ul>
<h3>11.过渡动画</h3>
<p>在插入和移除或者显示和隐藏DOM元素时，通过Vue的过渡动画系统，可以给元素添加三种类型的动画：CSS过渡（trasition或者animateframe），JavaScript过渡和渐进过渡。v-if、v-show、v-for（可以使用 vue-animated-list插件）三个指令可以使用过渡动画。</p>
<p>只需要在元素上添加transition属性即可应用过渡动画</p>
<pre class="hljs undefined"><code class="html">&lt;div v-if="show" transition="my-transition"&gt;&lt;/div&gt;</code></pre>
<h4>11.1 CSS transition</h4>
<p>在元素上添加transition属性</p>
<pre class="hljs undefined"><code class="html">&lt;div v-if="show" transition="expand"&gt;&lt;/div&gt;</code></pre>
<p>然后添加CSS过渡动画</p>
<pre class="hljs css"><code class="css"><span class="hljs-comment">/* 必需 */</span>
<span class="hljs-selector-class">.expand-transition</span> {
  <span class="hljs-attribute">transition</span>: all .<span class="hljs-number">3s</span> ease;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">30px</span>;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">10px</span>;
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#eee</span>;
  <span class="hljs-attribute">overflow</span>: hidden;
}
<span class="hljs-comment">/* .expand-enter 定义进入的开始状态 */</span>
<span class="hljs-comment">/* .expand-leave 定义离开的结束状态 */</span>
<span class="hljs-selector-class">.expand-enter</span>, <span class="hljs-selector-class">.expand-leave</span> {
  <span class="hljs-attribute">height</span>: <span class="hljs-number">0</span>;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">0</span> <span class="hljs-number">10px</span>;
  <span class="hljs-attribute">opacity</span>: <span class="hljs-number">0</span>;
}</code></pre>
<p>如果transition属性没有值，则默认的CSS类名是<code>.v-transition</code>, <code>.v-enter</code> 和 <code>.v-leave</code>。默认的进入和退出动画都是<code>*-leave</code>的形式，如果希望使用其它的CSS类名，则可以自定义，这样便能很好配合第三方CSS库比如animate.css</p>
<pre class="hljs javascript"><code class="javascript">Vue.transition(<span class="hljs-string">'bounce'</span>, {
    <span class="hljs-attr">enterClass</span>: <span class="hljs-string">'bounceInLeft'</span>,
    <span class="hljs-attr">leaveClass</span>: <span class="hljs-string">'bounceOutRight'</span>
});</code></pre>
<pre class="hljs undefined"><code class="html">&lt;div v-show="ok" class="animated" transition="bounce"&gt;Watch me bounce&lt;/div&gt;</code></pre>
<h4>11.2 CSS animation</h4>
<p>用法与CSS transition一样，唯一的区别是CSS transition依靠删除类名来触发transition，元素一插入文档便即刻删除类名；而CSS animation则是在CSS动画的<code>animationend</code>事件中来删除类名，因为它需要等到动画运行结束才能删除，否则动画不起效</p>
<pre class="hljs undefined"><code class="html">&lt;span v-show="show" transition="bounce"&gt;Look at me!&lt;/span&gt;</code></pre>
<pre class="hljs css"><code class="css"><span class="hljs-selector-class">.bounce-transition</span> {
  <span class="hljs-attribute">display</span>: inline-block; <span class="hljs-comment">/* 否则 scale 动画不起作用 */</span>
}
<span class="hljs-selector-class">.bounce-enter</span> {
  <span class="hljs-attribute">animation</span>: bounce-in .<span class="hljs-number">5s</span>;
}
<span class="hljs-selector-class">.bounce-leave</span> {
  <span class="hljs-attribute">animation</span>: bounce-out .<span class="hljs-number">5s</span>;
}
@<span class="hljs-keyword">keyframes</span> bounce-in {
  0% {
    <span class="hljs-attribute">transform</span>: <span class="hljs-built_in">scale</span>(0);
  }
  50% {
    <span class="hljs-attribute">transform</span>: <span class="hljs-built_in">scale</span>(1.5);
  }
  100% {
    <span class="hljs-attribute">transform</span>: <span class="hljs-built_in">scale</span>(1);
  }
}
@<span class="hljs-keyword">keyframes</span> bounce-out {
  0% {
    <span class="hljs-attribute">transform</span>: <span class="hljs-built_in">scale</span>(1);
  }
  50% {
    <span class="hljs-attribute">transform</span>: <span class="hljs-built_in">scale</span>(1.5);
  }
  100% {
    <span class="hljs-attribute">transform</span>: <span class="hljs-built_in">scale</span>(0);
  }
}</code></pre>
<h4>11.3 显示地声明是CSS过渡还是CSS动画</h4>
<p>如果只使用了css transtion或者css animation其中一个来实现动画，则vue会根据css样式自动判断是哪种类型的动画，从而监听对应的事件（transitionend或者animationend）。</p>
<p>但是有时会出现冲突，比如你使用了css animation来实现动画，但是又定义了鼠标悬停时的css transition动画，这时这两类事件都会被该元素触发，则你需要显示地声明vue应该监听哪类事件：</p>
<pre class="hljs javascript"><code class="javascript">Vue.transition(<span class="hljs-string">'bounce'</span>, {
  <span class="hljs-comment">// 该过渡效果将只侦听 `animationend` 事件</span>
  type: <span class="hljs-string">'animation'</span>
})</code></pre>
<h4>11.4 动画各阶段回调函数</h4>
<p>在动画的各个阶段都可以提供回调函数，vue会在相应的动画阶段调用它们：</p>
<pre class="hljs javascript"><code class="javascript">Vue.transition(<span class="hljs-string">'expand'</span>, {
  <span class="hljs-attr">beforeEnter</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">el</span>) </span>{
    el.textContent = <span class="hljs-string">'beforeEnter'</span>
  },
  <span class="hljs-attr">enter</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">el</span>) </span>{
    el.textContent = <span class="hljs-string">'enter'</span>
  },
  <span class="hljs-attr">afterEnter</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">el</span>) </span>{
    el.textContent = <span class="hljs-string">'afterEnter'</span>
  },
  <span class="hljs-attr">enterCancelled</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">el</span>) </span>{
    <span class="hljs-comment">// handle cancellation</span>
  },

  <span class="hljs-attr">beforeLeave</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">el</span>) </span>{
    el.textContent = <span class="hljs-string">'beforeLeave'</span>
  },
  <span class="hljs-attr">leave</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">el</span>) </span>{
    el.textContent = <span class="hljs-string">'leave'</span>
  },
  <span class="hljs-attr">afterLeave</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">el</span>) </span>{
    el.textContent = <span class="hljs-string">'afterLeave'</span>
  },
  <span class="hljs-attr">leaveCancelled</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">el</span>) </span>{
    <span class="hljs-comment">// handle cancellation</span>
  }
})</code></pre>
<h4>11.5 JavaScript过渡</h4>
<p>既然在动画的各个阶段都有回调函数，自然，我们完全可以不定义任何CSS，直接使用JavaScript来定义元素动画。注意，enter和leave需要调用done回调函数，否则动画将立即结束。</p>
<pre class="hljs javascript"><code class="javascript">Vue.transition(<span class="hljs-string">'fade'</span>, {
  <span class="hljs-attr">css</span>: <span class="hljs-literal">false</span>, <span class="hljs-comment">// 显示地声明为非css回调，vue将跳过css检测，同时也能防止css规则干扰过渡</span>
  enter: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">el, done</span>) </span>{
    <span class="hljs-comment">// 元素已被插入 DOM</span>
    <span class="hljs-comment">// 在动画结束后调用 done</span>
    $(el)
      .css(<span class="hljs-string">'opacity'</span>, <span class="hljs-number">0</span>)
      .animate({ <span class="hljs-attr">opacity</span>: <span class="hljs-number">1</span> }, <span class="hljs-number">1000</span>, done)
  },
  <span class="hljs-attr">enterCancelled</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">el</span>) </span>{
    $(el).stop()
  },
  <span class="hljs-attr">leave</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">el, done</span>) </span>{
    <span class="hljs-comment">// 与 enter 相同</span>
    $(el).animate({ <span class="hljs-attr">opacity</span>: <span class="hljs-number">0</span> }, <span class="hljs-number">1000</span>, done)
  },
  <span class="hljs-attr">leaveCancelled</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">el</span>) </span>{
    $(el).stop()
  }
})</code></pre>
<h4>11.6 动态绑定transition</h4>
<p>你可以在同一元素上通过动态绑定实现不同的过渡：</p>
<pre class="hljs undefined"><code class="html">&lt;div v-if="show" :transition="transitionName"&gt;hello&lt;/div&gt;</code></pre>
<pre class="hljs javascript"><code class="javascript"><span class="hljs-keyword">new</span> Vue({
  <span class="hljs-attr">el</span>: <span class="hljs-string">'...'</span>,
  <span class="hljs-attr">data</span>: {
    <span class="hljs-attr">show</span>: <span class="hljs-literal">false</span>,
    <span class="hljs-attr">transitionName</span>: <span class="hljs-string">'fade'</span>
  }
})</code></pre>
<h4>11.7 渐进过渡</h4>
<p><code>transition</code>与<code>v-for</code>一起用时可以创建渐近过渡。所谓渐进过渡，即每个元素进入或退出都比上一元素延迟一点，不是同时进入或退出。只需要给过渡元素添加一个特性<code>stagger</code>，<code>enter-stagger</code> 或<code>leave-stagger</code>，即可添加渐进过渡：</p>
<pre class="hljs undefined"><code class="html">&lt;div v-for="item in list" transition="stagger" stagger="100"&gt;&lt;/div&gt;</code></pre>
<p>或者提供一个钩子 stagger, enter-stagger 或 leave-stagger，以更好的控制：</p>
<pre class="hljs javascript"><code class="javascript">Vue.transition(<span class="hljs-string">'stagger'</span>, {
  <span class="hljs-attr">stagger</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">index</span>) </span>{
    <span class="hljs-comment">// 每个过渡项目增加 50ms 延时</span>
    <span class="hljs-comment">// 但是最大延时限制为 300ms</span>
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">Math</span>.min(<span class="hljs-number">300</span>, index * <span class="hljs-number">50</span>)
  }
})</code></pre>
<h3>12.组件</h3>
<p>使用组件来封装可重用的代码，使用<code>Vue.extend()</code>来构造组件，使用<code>Vue.component()</code>或者选项对象中的<code>components</code>属性来注册组件，使用自定义标签<code>&lt;component-name&gt;&lt;/component-name&gt;</code>来使用组件</p>
<h4>12.1 基本使用</h4>
<p>组件的使用分为3个步骤：</p>
<ol>
<li>定义组件<pre class="hljs javascript"><code class="javascript"><span class="hljs-keyword">var</span> MyComponent = Vue.extend({
       <span class="hljs-attr">template</span>: <span class="hljs-string">'&lt;div&gt;A custom component!&lt;/div&gt;'</span>
     })</code></pre>
</li>
<li>
<p>注册组件</p>
<pre class="hljs javascript"><code class="javascript">Vue.component(<span class="hljs-string">'my-component'</span>, MyComponent) <span class="hljs-comment">// 全局注册</span>
<span class="hljs-keyword">var</span> Parent = Vue.extend({
<span class="hljs-attr">template</span>: <span class="hljs-string">'...'</span>,
<span class="hljs-attr">components</span>: {
 <span class="hljs-comment">// &lt;my-component&gt; 只能用在父组件模板内</span>
 <span class="hljs-string">'my-component'</span>: Child
}
})</code></pre>
<p>组件可以注册在全局，也可以注册在另一个组件内。在哪注册则仅能在该作用域使用</p>
<p>Vue.extend()可以将组件的注册和定义一次写完，只需要将定义组件时传入给extend()的对象直接传递给components内即可</p>
<pre class="hljs javascript"><code class="javascript"><span class="hljs-keyword">var</span> Parent = Vue.extend({
<span class="hljs-attr">template</span>: <span class="hljs-string">'...'</span>,
<span class="hljs-attr">components</span>: {
 <span class="hljs-comment">// &lt;my-component&gt; 只能用在父组件模板内</span>
 <span class="hljs-string">'my-component'</span>: {
     <span class="hljs-attr">template</span>: <span class="hljs-string">'&lt;div&gt;A custom component!&lt;/div&gt;'</span>
 }
}
})</code></pre>
</li>
<li>使用组件<pre class="hljs undefined"><code class="html">&lt;div id="example"&gt;
&lt;my-component&gt;&lt;/my-component&gt;
&lt;/div&gt;</code></pre>
</li>
</ol>
<h4>12.2 选项和模板解析注意事项：</h4>
<ul>
<li>组件选项。大部分用于<code>new Vue()</code>的选项都可以在构造组件时使用，但有两个特例：<code>data</code>和<code>el</code>，它们在vue()构造器中是对象或者对象的引用，如果组件也这么用，将造成所有组件共享一个对象引用的结果，组件之间存在干扰，所以这两个选项需要使用函数返回新对象<pre class="hljs javascript"><code class="javascript"><span class="hljs-keyword">var</span> MyComponent = Vue.extend({
<span class="hljs-attr">data</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> { <span class="hljs-attr">a</span>: <span class="hljs-number">1</span> }
}
})</code></pre>
</li>
<li>Vue使用的是DOM模板而非字符串模板，也就是说Vue内部处理的是真正的DOM元素而不是处理字符串。而DOM模板的一个重要限制就是它必须是有效的HTML片段，而很多DOM元素都对内部的子元素类型有限制，比如：<pre class="hljs undefined"><code>a 不能包含其它的交互元素（如按钮，链接）
ul 和 ol 只能直接包含 li
select 只能包含 option 和 optgroup
table 只能直接包含 thead, tbody, tfoot, tr, caption, col, colgroup
tr 只能直接包含 th 和 td</code></pre>
所以对模板的使用限制就很明显了，自定义元素和特殊元素不能作为像<code>table</code>这样对内部元素有限制的元素的直接子元素，也不能作为像<code>option</code>这样只能作为<code>select</code>子元素的元素的父元素（违反这个规则将渲染不正确）</li>
</ul>
<p>当需要将某个限制类的元素用作模板时，使用is指令来规避以上限制：</p>
<pre class="hljs undefined"><code class="html">&lt;table&gt;
  &lt;tr is='my-component'&gt;&lt;/tr&gt;
&lt;/table&gt;</code></pre>
<h4>12.3 向组件传递数据</h4>
<h5>12.3.1 基本用法</h5>
<p>组件实例的作用域是孤立的，但可以通过组件的props属性向组件传递数据：</p>
<pre class="hljs javascript"><code class="javascript">Vue.component(<span class="hljs-string">'child'</span>, {
  <span class="hljs-attr">template</span>: <span class="hljs-string">"&lt;p&gt;msg&lt;/p&gt;"</span>,
  <span class="hljs-attr">props</span>: [<span class="hljs-string">'msg'</span>] <span class="hljs-comment">// props中数据的读写与data属性中的数据一致</span>
});</code></pre>
<pre class="hljs undefined"><code class="html">&lt;child msg='hello!'&gt;&lt;/child&gt; &lt;!--在父组件中向子组件传递数据--&gt;</code></pre>
<h5>12.3.2 驼峰和短横线</h5>
<p>当使用驼峰写法声明props属性时，在使用该属性传递数据时需要写为短横线格式：</p>
<pre class="hljs javascript"><code class="javascript">...
props: [<span class="hljs-string">'myProp'</span>],
...</code></pre>
<pre class="hljs undefined"><code class="html">&lt;child my-prop='hello!'&gt;&lt;/child&gt;</code></pre>
<h5>12.3.3 动态绑定和单向/双向绑定</h5>
<p>使用v-bind可以在父组件向子组件中传递动态数据或者实际的值而不是字符串：</p>
<pre class="hljs undefined"><code class="html">&lt;child :my-prop="someDataFromFather"&gt;&lt;/child&gt; &lt;!--传递动态数据--&gt;
&lt;child :my-prop="{ a:1, b:2 }"&gt;&lt;/child&gt; &lt;!--传递实际的值--&gt;</code></pre>
<p>绑定动态数据时，props默认是单向绑定，父组件的数据变化会传递并反映在子组件中，也可以使用.async修饰符强制双向绑定，子组件中改变props的值也会反映在父组件中，单并不推荐，因为会让数据流不好理解</p>
<pre class="hljs undefined"><code class="html">&lt;child :my-prop.async="someDataFromFather"&gt;&lt;/child&gt; &lt;!--传递实际的值--&gt;</code></pre>
<h5>12.3.4 验证规则</h5>
<p>可以为props指定验证规则，props设置不再是数组而是对象，每个prop都是一个规定了验证要求的对象，可以设置的验证要求包括：</p>
<pre class="hljs undefined"><code>* type：基础类型检测，可以设置为String、Number、Boolean、Function、Object、Array，当只需要这一个验证时可直接设置prop: String，如果可以是多种类型，则可设置prop: [Number, String]
* required：是否必须，boolean
* default：默认值
* twoWay：是否双向
* validator：自定义验证函数
* coerce：自定义转换函数，在设置之前转换值</code></pre>
<p>当prop验证失败了，Vue将拒绝在子组件上设置此值，如果使用的是开发版本会抛出一条警告<br>另外需要注意，<code>props</code>的<code>defalut</code>可以使用一个<code>function</code>动态返回一个值，所以如果期望一个prop是function类型，则应当在匿名函数中返回这个function</p>
<h4>12.4 组件树通信</h4>
<p>除了props属性能够让父子组件之间通信外，还有下面的一些方式能够在组件树种进行通信</p>
<h5>12.4.1 父链——父子组件互相访问</h5>
<pre class="hljs undefined"><code>* 子组件可以通过this.$parent访问父组件
* 父组件通过this.$children访问包含了所有子组件的数组
* 根实例后代通过this.$root访问根实例（也即new Vue()）
* 尽可能避免使用父链进行通信，应当尽可能使用props显示声明</code></pre>
<h5>12.4.2 自定义事件——异步事件通信机制</h5>
<p>Vue实现了一套自定义事件接口用于组件树通信，独立于DOM事件</p>
<pre class="hljs undefined"><code>* 触发事件：
    * $emit() 触发事件，子组件事件只能在子组件中被监听
    * $dispatch() 派发事件，事件沿着父链冒泡，子组件事件可以在父组件中监听
    * $broadcast() 广播事件，事件向下传递给所有后代，父组件事件可以在子组件中被监听
* 监听事件：
    * $on() 监听事件
    * events选项监听事件
    * v-on指令监听事件</code></pre>
<p>注意，Vue事件会在冒泡后第一次触发执行事件处理函数后停止冒泡，除非在事件处理函数中显式返回true</p>
<p>Vue官方推荐当一个子组件派发事件后，在父组件中使用子组件的时候<code>v-on</code>监听，是最直观的方式，因为这样能够直观知道事件来自哪里：</p>
<pre class="hljs undefined"><code class="html">&lt;child :msg="hello!" v-on:customEvent="handler"&gt;&lt;/child&gt;</code></pre>
<h5>12.4.3 子组件索引——父组件直接访问子组件</h5>
<p>有时仍需要在JavaScript中直接访问子组件，可以使用v-ref指令指定子组件索引</p>
<pre class="hljs undefined"><code class="html">&lt;child v-ref:profile&gt;&lt;/child&gt;</code></pre>
<p>然后在注册它的父级中直接访问：</p>
<pre class="hljs javascript"><code class="javascript"><span class="hljs-keyword">var</span> child =  parent.$refs.profile</code></pre>
<p>当和v-for一起使用时是一个数组或者对象，包含相应的子组件</p>
<h5>12.4.4 使用<code>slot</code>分发内容——父组件向子组件下发内容</h5>
<p>当你的子组件有容器的功能时，子组件的部分内容（通常是html结构）就不确定了，比如你定义了一个列表组件，但是你希望你的列表中每一项的内容能够在使用组件的时候给定，而不是写死在组件中，这时就需要用到<code>slot</code>来向组件内分发内容，唯一需要记住的是：</p>
<blockquote><p>父组件模板的内容在父组件作用域内编译，子组件模板中的内容在子组件作用域内编译<br>slot中的分发内容是在父组件中编译的</p></blockquote>
<ul>
<li>
<p>定义slot接口（在组件内）：</p>
<pre class="hljs undefined"><code class="html">&lt;!-- 单个slot --&gt;
&lt;template&gt;
&lt;div&gt;
  &lt;slot&gt;&lt;/slot&gt;
&lt;/div&gt;
&lt;/template&gt;</code></pre>
<pre class="hljs undefined"><code class="html">&lt;template&gt;
&lt;!-- 多个slot（具名slot） --&gt;
&lt;div&gt;
  &lt;slot name="title"&gt;&lt;/slot&gt;
  &lt;p&gt;ajsf  ah  askhjdf a askjfh a fhasdkfu9fa ajsh ia uiasd gak jgasdfh la ioa akjsflai a&lt;/p&gt;
  &lt;slot name="footer"&gt;&lt;/slot&gt;
&lt;/div&gt;
&lt;/template&gt;</code></pre>
</li>
<li>
<p>使用slot接口（使用组件时）：</p>
<pre class="hljs undefined"><code class="html">&lt;!-- 单个slot --&gt;
&lt;my-component&gt;
&lt;p&gt;这里的所有内容都将插入组件的slot中&lt;p&gt;
&lt;div&gt;这里的所有内容都将插入组件的slot中&lt;/div&gt;
&lt;/my-component&gt;</code></pre>
<pre class="hljs undefined"><code class="html">&lt;!-- 多个slot（具名slot） --&gt;
&lt;my-component&gt;
&lt;p slot="title"&gt;这里的内容将插入组件的name="title"的slot中&lt;p&gt;
&lt;div slot="footer"&gt;这里的所有内容将插入组件的name="footer"的slot中&lt;/div&gt;
&lt;p&gt;这里的内容将被插入组件中未署名的slot中，如果没有未署名的slot则将被忽略&lt;/p&gt;
&lt;/my-component&gt;</code></pre>
</li>
</ul>
<h5>12.4.5 动态组件</h5>
<p>可以将多个组件挂在到同一个挂载点上，然后动态切换它们。使用保留的&lt;component&gt;元素，将组件动态地绑定到它的is属性上：</p>
<pre class="hljs javascript"><code class="javascript"><span class="hljs-keyword">new</span> Vue({
  <span class="hljs-attr">el</span>: <span class="hljs-string">'body'</span>,
  <span class="hljs-attr">data</span>: {
    <span class="hljs-attr">currentView</span>: <span class="hljs-string">'home'</span>
  },
  <span class="hljs-attr">components</span>: {
    <span class="hljs-attr">home</span>: { <span class="hljs-comment">/* ... */</span> },
    <span class="hljs-attr">posts</span>: { <span class="hljs-comment">/* ... */</span> },
    <span class="hljs-attr">archive</span>: { <span class="hljs-comment">/* ... */</span> }
  }
})</code></pre>
<pre class="hljs undefined"><code class="html">&lt;component :is="currentView"&gt;
  &lt;!-- 组件在 vm.currentview 变化时改变 --&gt;
&lt;/component&gt;</code></pre>
<p>可以使用<code>keep-alive</code>指令将切换出去的组件保留在内存中，避免重新渲染并且保留它的状态</p>
<pre class="hljs undefined"><code class="html">&lt;component :is="currentView" keep-alive&gt;&lt;/component&gt;</code></pre>
<p>组件中可以使用<code>activate</code>钩子来在切入前做一些事情，通常是异步操作比如加载数据等等：</p>
<pre class="hljs javascript"><code class="javascript">Vue.component(<span class="hljs-string">'activate-example'</span>, {
  <span class="hljs-attr">activate</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">done</span>) </span>{
    <span class="hljs-keyword">var</span> self = <span class="hljs-keyword">this</span>
    loadDataAsync(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">data</span>) </span>{
      self.someData = data
      done()
    })
  }
})</code></pre>
<p>组件还可以使用<code>transition</code>、<code>transition-mode</code>两个属性来指定动态组件的过场动画，transition的使用和普通元素一致，<code>trnasition-mode</code>为可选项，不指定时默认是进入与离开的组件同时开始过渡，指定为<code>in-out</code>和<code>out-in</code>则分别是先进后出或先出后进。唯一需要注意的是，动态组件不能是片段实例（没有唯一的父级元素），否则<code>transition</code>将不起作用</p>
<p>vue-router的<code>&lt;route-view&gt;&lt;/route-view&gt;</code>便是利用了动态组件的特性，所有用于动态组件的属性都可以用于route-view</p>
<h4>12.5 杂项</h4>
<h5>12.5.1 组件和<code>v-for</code>
</h5>
<p>组件可以使用<code>v-for</code>，<code>v-for</code>中的<code>item</code>数据应当也只能使用组件的<code>props</code>属性传递给组件</p>
<h5>12.5.2 编写可复用组件</h5>
<p>如果你的组件是需要复用的，则应当尽可能与其它组件解耦，定义好清晰的公开接口：<code>props</code>、事件、<code>slot</code>，使用组件时使用<code>v-bind</code>和<code>v-on</code>的简写<code>@</code>和<code>:</code>，并清晰的进行缩进</p>
<h5>12.5.3 异步组件</h5>
<p>可以让组件只在需要时从服务器下载，vue允许将组建定义为一个工厂函数，只在第一次需要渲染时触发工厂函数从服务器下载并缓存结果供多次渲染使用</p>
<pre class="hljs javascript"><code class="javascript">Vue.component(<span class="hljs-string">'async-component-example'</span>, (resolve, reject) =&gt; {
  setTimeout(<span class="hljs-function"><span class="hljs-params">()</span> =&gt;</span> { <span class="hljs-comment">// 假装是在从服务器下载 O(∩_∩)O哈哈哈~</span>
    resolve({ <span class="hljs-comment">// 将下载好的组件传递出去</span>
      template: <span class="hljs-string">'&lt;div&gt;I am async!&lt;/div&gt;'</span>
    })
    <span class="hljs-comment">// 当然也可以调用reject()提示加载失败</span>
  }, <span class="hljs-number">1000</span>)
})</code></pre>
<p>这个功能可以与Webpack的代码分隔功能配合使用</p>
<pre class="hljs javascript"><code class="javascript">Vue.component(<span class="hljs-string">'async-webpack-example'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">resolve</span>) </span>{
  <span class="hljs-comment">// 这个特殊的 require 语法告诉 webpack</span>
  <span class="hljs-comment">// 自动将编译后的代码分割成不同的块，</span>
  <span class="hljs-comment">// 这些块将通过 ajax 请求自动下载。</span>
  <span class="hljs-built_in">require</span>([<span class="hljs-string">'./my-async-component'</span>], resolve)
})</code></pre>
<h5>12.5.4 命名约定</h5>
<p>HTML中元素的属性名是不区分大小写的，但是当在定义组件挂载名称、props属性和事件名等等需要在HTML中使用的资源时，也可以使用驼峰命名（camelCase），只是使用的时候需要转成中划线命名（kebab-case）</p>
<h5>12.5.5 递归调用</h5>
<p>组件可以在自己的template中递归调用自己，但是需要注意，只有拥有name属性的组件才能递归调用自己（否则在自己的模板中没有挂载名可使用），并且要确保递归调用有终止条件</p>
<h5>12.5.6 片段实例</h5>
<p>当一个组件满足以下条件时，即为片段实例</p>
<ul>
<li>模板包含多个顶级元素。</li>
<li>模板只包含普通文本。</li>
<li>模板只包含其它组件（其它组件可能是一个片段实例）。</li>
<li>模板只包含一个元素指令，如 &lt;partial&gt; 或 vue-router 的 &lt;router-view&gt;。</li>
<li>模板根节点有一个流程控制指令，如 v-if 或 v-for。</li>
</ul>
<p>片段实例虽然可以正确渲染，但是存在如下问题：</p>
<ul>
<li>非流程控制指令将被忽略</li>
<li>非props特性将被忽略</li>
<li>transition属性将被忽略<br>内联模板</li>
</ul>
<p>如果组件有<code>inline-template</code>属性，则挂载组件时组件标签之间中内容将被作为组件的模板进行渲染，也就是说，你可以在调用组件时动态地定义组件的模板，这给了组件极大的灵活性。但缺点是模板编译结果不能被缓存，并且模板的作用域也不好理解了</p>
<h3>13.深入响应式原理</h3>
<h4>13.1 追踪数据变化</h4>
<p>在初始化vue实例时，vue会遍历实例的data选项并使用Object.defineProperty()来将data的各个属性转换为getter/setter（存取器属性，这也是vue不支持IE8及更早版本的原因）</p>
<p>使用vm.$log()方法可以将实例的data更为友好地打印到控制台</p>
<p>绑定到DOM中的每个数据或指令都有一个对应的watcher，它将数据和DOM中的绑定联系起来（把属性记录为依赖）：每次数据变化时，它的setter都会通知watcher，watcher再通知DOM进行更新</p>
<h4>13.2 检测数据变化的问题</h4>
<p>实例化之后响应式属性的添加：</p>
<p>vue只能在初始化vue实例的时候将数据转换为响应式的，如果初始化之后再向<code>data</code>中添加属性，则该属性不会是响应的而是普通属性，所以vue提供了在实例创建后继续向<code>data</code>添加响应属性的方法：<code>vm.$set()</code>和<code>Vue.set()</code><br>vue实例可以使用$set()来继续添加响应属性</p>
<pre class="hljs javascript"><code class="javascript">vm.$set(propName, value)</code></pre>
<p>对于普通的数据对象，可以使用全局方法Vue.set()来添加响应属性</p>
<pre class="hljs javascript"><code class="javascript">Vue.set(object, key, value)</code></pre>
<p>另外，如果向data中已有的对象上添加新的属性，比如使用Object.assign()或_.extend()添加属性，新添加的属性也不会是动态的，这时可以创建一个包含该属性的新对象，替换原有的data中对象</p>
<h4>13.3 事先声明所有属性（数据）</h4>
<p>尽可能不要使用<code>$set</code>在实例化后再次添加新的属性，而是应该在vue实例选项中事先全部声明好，这会让代码更易于理解。</p>
<p>另外添加一个顶级响应属性会强制所有watcher重新计算，因为添加之前它不存在，也没有watcher追踪它，添加它以后之前的依赖需要重新计算，虽然这对比Angular1的脏检查性能还是可以接受的，但仍旧可以在初始化之前全部声明好来避免这部分性能开销</p>
<h4>13.4 异步队列更新</h4>
<p>vue内部使用一个队列来异步地更新DOM，如果一个watcher被多次触发，只会推入一次到队列中，只进行必要的DOM更新。异步队列中优先使用<code>MutationObserver</code>，如果不支持则使用<code>setTimeout(fn, 0)</code>。</p>
<p>本次队列里的所有DOM更新操作，不会立即执行，而是在下次事件循环清空队列前更新。明白这一点，我们便可以合理地使用vue给出的<code>Vue.nextTick(callback)</code>方法，在更新完成DOM后做一些事情</p>
<p>该方法在vue实例上也有，并且更方便，因为回调的this自动指向了当前的vue实例对象</p>
<h4>13.5 计算属性</h4>
<p>计算属性不是简单的getter，计算属性持续追踪它的依赖，只要依赖变化了，计算属性就变化。</p>
<p>并且计算属性会缓存计算结果，除非依赖发生变化，否则读取计算属性时只从缓存读取（性能最优）</p>
<p>明白这一点，就能明白为什么计算属性的getter不是每次都会被调用：当你在计算属性的getter中new Date()时，并不是每次的值都是当前时间，它可能不会变化，还是过去的某个时间。如果不希望缓存，可以在设置计算属性时关闭缓存：</p>
<pre class="hljs javascript"><code class="javascript">computed: {
  <span class="hljs-attr">example</span>: {
    <span class="hljs-attr">cache</span>: <span class="hljs-literal">false</span>,
    <span class="hljs-attr">get</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
      <span class="hljs-keyword">return</span> <span class="hljs-built_in">Date</span>.now() + <span class="hljs-keyword">this</span>.msg
    }
  }
}</code></pre>
<p>然而即使关闭缓存，也仅仅是在js中读取这个属性时是实时的，DOM中的数据绑定仍旧是依赖驱动的，只有计算属性的依赖发生了变化，DOM才会更新。</p>
<h3>14.自定义指令</h3>
<p>除了内置指令，还可以自定义指令。使用<code>Vue.directive(id, definition)</code>方法注册全局自定义指令<br>使用组件的<code>directives</code>选项注册局部自定义指令</p>
<h4>14.1 钩子函数</h4>
<ul>
<li>bind：只调用一次，在指令第一次绑定到元素时调用</li>
<li>update：当绑定值变化时调用，参数为新值与旧值，第一次调用（bind之后会立即调用一次）时只有初始值，没有旧值<br>*unbind：只调用一次，在指令从元素上解绑是调用<pre class="hljs javascript"><code class="javascript">Vue.directive(<span class="hljs-string">'my-directive'</span>, {
<span class="hljs-attr">bind</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
  <span class="hljs-comment">// 准备工作</span>
  <span class="hljs-comment">// 例如，添加事件处理器或只需要运行一次的高耗任务</span>
},
<span class="hljs-attr">update</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">newValue, oldValue</span>) </span>{
  <span class="hljs-comment">// 值更新时的工作</span>
  <span class="hljs-comment">// 也会以初始值为参数调用一次</span>
},
<span class="hljs-attr">unbind</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
  <span class="hljs-comment">// 清理工作</span>
  <span class="hljs-comment">// 例如，删除 bind() 添加的事件监听器</span>
}
})</code></pre>
当注册以后，便可以在模板中像使用内置指令一样使用自定义指令：<pre class="hljs undefined"><code class="html">&lt;div v-my-directive="someValue"&gt;&lt;/div&gt;</code></pre>
当只需要update函数时，可以只传入一个函数替代definition对象</li>
</ul>
<h4>14.2 指令实例属性</h4>
<p>在钩子函数中，this指向当前的指令实例，指令实例上暴露了一些有用的属性：</p>
<ul>
<li>el: 指令绑定的元素。</li>
<li>vm: 拥有该指令的上下文 ViewModel。</li>
<li>expression: 指令的表达式，不包括参数和过滤器，表达式可以是任意合法的JavaScript表达式</li>
<li>arg: 指令的参数。</li>
<li>name: 指令的名字，不包含前缀。</li>
<li>modifiers: 一个对象，包含指令的修饰符。</li>
<li>descriptor: 一个对象，包含指令的解析结果。</li>
</ul>
<p>这些属性应当被当做只读的，不应该修改他们，即使你给指令对象添加自定义属性，也要注意不要覆盖这些内部属性</p>
<h4>14.3 元素指令</h4>
<p>元素指令可以看做是一个轻量的组件，它是以自定义元素的形式使用指令，而不是以特性的形式。使用<code>Vue.elementDirective(id, discription)</code>来注册自定义指令</p>
<pre class="hljs javascript"><code class="javascript">Vue.elementDirective(<span class="hljs-string">'my-directive'</span>, {
  <span class="hljs-comment">// API 同普通指令</span>
  bind: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{ <span class="hljs-comment">// 注意使用简写函数时this的指向</span>
    <span class="hljs-comment">// 操作this.el</span>
  }
})</code></pre>
<p>使用时便如同自定义元素：</p>
<pre class="hljs undefined"><code class="html">&lt;my -directive&gt;&lt;/my-directive&gt;</code></pre>
<p>所以元素指令不接受参数或表达式，只能读取元素属性来进行操作</p>
<p>元素指令是终结性的，一旦Vue遇到一个元素指令它将跳过该院故事及其子元素，而将它们留给指令本身去操作</p>
<h4>14.4 高级选项</h4>
<h5>14.4.1 params特性列表</h5>
<p>自定义指令可以接收一个params数组，指定一个特性列表，Vue编译器将自动提取这些特性：</p>
<pre class="hljs undefined"><code class="html">&lt;div v-example a="hi"&gt;&lt;/div&gt;</code></pre>
<pre class="hljs javascript"><code class="javascript">Vue.directive(<span class="hljs-string">'example'</span>, {
  <span class="hljs-attr">params</span>: [<span class="hljs-string">'a'</span>],
  <span class="hljs-attr">bind</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    <span class="hljs-built_in">console</span>.log(<span class="hljs-keyword">this</span>.params.a)
  }
})</code></pre>
<p>params中的属性也支持动态属性：</p>
<pre class="hljs undefined"><code class="html">&lt;div v-example :a="msg"&gt;&lt;/div&gt;</code></pre>
<pre class="hljs javascript"><code class="javascript">Vue.directive(<span class="hljs-string">'example'</span>, {
  <span class="hljs-attr">params</span>: [<span class="hljs-string">'a'</span>],
  <span class="hljs-attr">paramWatchers</span>: {
  <span class="hljs-attr">a</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">val, oldVal</span>) </span>{
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'a changed!'</span>)
  }
  }
})</code></pre>
<h5>14.4.2 deep深度检测</h5>
<p>如果自定义属性的值为一个对象，当希望对象内部属性发生变化时触发<code>update</code>，则在定义指令时指定<code>deep:true</code></p>
<pre class="hljs undefined"><code class="html">&lt;div v-my-directive="obj"&gt;&lt;/div&gt;</code></pre>
<pre class="hljs javascript"><code class="javascript">Vue.directive(<span class="hljs-string">'my-directive'</span>, {
  <span class="hljs-attr">deep</span>: <span class="hljs-literal">true</span>,
  <span class="hljs-attr">update</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">obj</span>) </span>{
    <span class="hljs-comment">// 在obj的内部属性变化时调用</span>
  }
})</code></pre>
<h5>14.4.3 twoWay回写数据</h5>
<p>默认情况下指令中是不能向vm写入数据的，但是可以使用twoWay选项开启，这样指令中就可以使用<code>set()</code>方法向vm回写数据，前提是指令绑定的是vm中的数据属性</p>
<pre class="hljs javascript"><code class="javascript">Vue.directive(<span class="hljs-string">'example'</span>, {
  <span class="hljs-attr">towWay</span>: <span class="hljs-literal">true</span>,
  <span class="hljs-attr">bind</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">this</span>.handler = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
      <span class="hljs-comment">// 将数据写回 vm</span>
      <span class="hljs-comment">// 如果指令这样绑定 v-example="a.b.c"</span>
      <span class="hljs-comment">// 它将用给定值设置 `vm.a.b.c`</span>
      <span class="hljs-keyword">this</span>.set(<span class="hljs-keyword">this</span>.value)
    }.bind(<span class="hljs-keyword">this</span>)
    <span class="hljs-keyword">this</span>.el.addEventListener(<span class="hljs-string">'input'</span>, <span class="hljs-keyword">this</span>.handler)
  },
  <span class="hljs-attr">unbind</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">this</span>.el.removeEventListener(<span class="hljs-string">'input'</span>, <span class="hljs-keyword">this</span>.handler)
  }
})</code></pre>
<h5>14.4.4 acceptStatement</h5>
<p><code>acceptStatement:true</code>可以让自定义指令接受内联js语句（比如<code>v-on</code>），但需要注意内联语句的副作用</p>
<pre class="hljs javascript"><code class="javascript">Vue.directive(<span class="hljs-string">'my-directive'</span>, {
  <span class="hljs-attr">acceptStatement</span>: <span class="hljs-literal">true</span>,
  <span class="hljs-attr">update</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">fn</span>) </span>{
    <span class="hljs-comment">// 传入值是一个函数</span>
    <span class="hljs-comment">// 在调用它时将在所属实例作用域内计算 "a++" 语句</span>
  }
})</code></pre>
<h4>14.4.5 terminal</h4>
<p>（1.0.19+）<code>terminal: true</code>指定由指令来接管元素的编译（比如<code>v-if</code>和<code>v-for</code>）。可能还需要<code>Vue.FragmentFactory</code>来编译partial。需要较好了解Vue的编译流程（2.X中编译流程略有变化），建议通读<code>v-if</code>和<code>v-for</code>源码来写terminal指令</p>
<h4>14.4.6 优先级</h4>
<p>普通指令默认1000，terminal指令默认2000。在API文档中查看指令优先级。流程控制指令使用用友最高优先级。</p>
<h3>15. 自定义过滤器</h3>
<h4>15.1 注册单向过滤器</h4>
<p>使用<code>Vue.filter()</code>来注册自定义过滤器，第一个参数为过滤器名称，第二个参数为过滤器函数：</p>
<pre class="hljs javascript"><code class="javascript">Vue.filter(<span class="hljs-string">'wrap'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">value, begin, end</span>) </span>{ <span class="hljs-comment">// 过滤器函数接受任意数量参数</span>
  <span class="hljs-keyword">return</span> begin + value + end
})</code></pre>
<pre class="hljs undefined"><code class="html">&lt;!-- 'hello' =&gt; 'before hello after' --&gt;
&lt;span v-text="message | wrap 'before' 'after'"&gt;&lt;/span&gt;</code></pre>
<p>这个过滤器会将来自vm的数据处理后交给view显示。</p>
<h4>15.2 注册双向过滤器</h4>
<p>过滤器不仅可以处理从vm到view的数据，也可以处理从view到vm的数据。传递给<code>Vue.filter()</code>的第二个参数变为一个含有<code>read</code>和<code>write</code>方法的对象：</p>
<pre class="hljs javascript"><code class="javascript">Vue.filter(<span class="hljs-string">'currencyDisplay'</span>, {
  <span class="hljs-comment">// model -&gt; view</span>
  <span class="hljs-comment">// 在更新 `&lt;input&gt;` 元素之前格式化值</span>
  read: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">val</span>) </span>{
    <span class="hljs-keyword">return</span> <span class="hljs-string">'$'</span>+val.toFixed(<span class="hljs-number">2</span>)
  },
  <span class="hljs-comment">// view -&gt; model</span>
  <span class="hljs-comment">// 在写回数据之前格式化值</span>
  write: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">val, oldVal</span>) </span>{
    <span class="hljs-keyword">var</span> number = +val.replace(<span class="hljs-regexp">/[^\\\\\\\\d.]/g</span>, <span class="hljs-string">''</span>)
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">isNaN</span>(number) ? <span class="hljs-number">0</span> : <span class="hljs-built_in">parseFloat</span>(number.toFixed(<span class="hljs-number">2</span>))
  }
})</code></pre>
<p><strong>注意：</strong></p>
<ul>
<li>使用过滤器时的参数如果没有使用引号，则会在vm作用域内编译，使用引号则作为字符串传递给过滤器</li>
<li>过滤器只推荐简单逻辑使用，复杂的逻辑应当使用计算属性</li>
<li>过滤器函数中的this始终指向当前vm实例</li>
<li>内置过滤器<code>filterBy</code>和<code>orderBy</code>根据指定的方法过滤/排序传入的<strong>数组</strong>
</li>
</ul>
<h3>16. 混合</h3>
<h4>16.1 基本使用</h4>
<p>定义一个选项对象，然后在实例化vue时使用<code>mixins: [optionObj1, optionObj12]</code>来将选项混合到当前的vue实例选项中：</p>
<pre class="hljs javascript"><code class="javascript"><span class="hljs-comment">// 定义一个混合对象</span>
<span class="hljs-keyword">var</span> myMixin = {
  <span class="hljs-attr">created</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">this</span>.hello()
  },
  <span class="hljs-attr">methods</span>: {
    <span class="hljs-attr">hello</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'hello from mixin!'</span>)
    }
  }
}

<span class="hljs-comment">// 定义一个组件，使用这个混合对象</span>
<span class="hljs-keyword">var</span> Component = Vue.extend({
  <span class="hljs-attr">mixins</span>: [myMixin]
})

<span class="hljs-keyword">var</span> component = <span class="hljs-keyword">new</span> Component() <span class="hljs-comment">// -&gt; "hello from mixin!"</span></code></pre>
<p>默认的合并策略是：</p>
<ul>
<li>同名钩子函数被并入一个数组，依次执行，混合的钩子先于组件自己的钩子执行</li>
<li>值为对象的选项将合并到同一个对象内，键名冲突则组件自己的选项优先</li>
<li>
<code>Vue.extend()</code>同样使用上述策略进行合并</li>
</ul>
<h4>16.2 自定义选项</h4>
<p>所谓自定义选项，是除开类似<code>data</code>，<code>methods</code>这样vue官方提供的选项，你希望使用的由你自己命名的选项。<br>通常情况下你在某个vue实例中使用了自定义选项，你可能对选项进行处理。但是如果你希望所有的vue实例在使用这个自定义选项时都做同样处理，这时你可以使用全局混合。</p>
<h5>16.2.1 全局混合</h5>
<p>可以使用<code>Vue.mixin()</code>来注册全局混合。<strong>所谓全局混合就是一旦注册，会应用到之后创建的所有vue实例上，所以需要小心使用</strong>。但这个特性特别适合用于为自定义选项注入处理逻辑，让它表现得像官方选项一样：</p>
<pre class="hljs javascript"><code class="javascript"><span class="hljs-comment">// 为 `myOption` 自定义选项注入一个处理器</span>
Vue.mixin({
  <span class="hljs-attr">created</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">var</span> myOption = <span class="hljs-keyword">this</span>.$options.myOption
    <span class="hljs-keyword">if</span> (myOption) {
      <span class="hljs-built_in">console</span>.log(myOption)
    }
  }
})

<span class="hljs-keyword">new</span> Vue({
  <span class="hljs-attr">myOption</span>: <span class="hljs-string">'hello!'</span>
})
<span class="hljs-comment">// -&gt; "hello!"</span></code></pre>
<h4>16.2.2 自定义选项合并策略</h4>
<p>混合时对自定义选项的处理只是简单地覆盖已有值，如果想用自定义逻辑合并自定义选项，则向<code>Vue.config.optionMergeStrategies</code>添加一个函数：</p>
<pre class="hljs javascript"><code class="javascript">Vue.config.optionMergeStrategies.myOption = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">toVal, fromVal</span>) </span>{
  <span class="hljs-comment">// 返回 mergedVal</span>
}</code></pre>
<p>对于多数值为对象的选项，可以简单地使用 methods 所用的合并策略：</p>
<pre class="hljs javascript"><code class="javascript"><span class="hljs-keyword">var</span> strategies = Vue.config.optionMergeStrategies
strategies.myOption = strategies.methods</code></pre>
<h3>17.其它</h3>
<p>插件、构建和对比其它框架三个主题略过，可去<a href="http://vuejs.org.cn/guide/plugins.html" target="_blank">官方文档</a>查看详细信息</p>

        </div>
        <!--  -->

        <div class="show-foot">
          <a class="notebook" href="http://www.jianshu.com/nb/6409590">
            <i class="iconfont ic-search-notebook"></i>
            <span>前端开发</span>
</a>          <div class="copyright" data-toggle="tooltip" data-html="true" data-original-title="转载请联系作者获得授权，并标注“简书作者”。">
            © 著作权归作者所有
          </div>
          <div class="modal-wrap" data-report-note="">
            <a id="report-modal">举报文章</a>
          </div>
        </div>
    </div>

    <!-- 文章底部作者信息 -->
      <div class="follow-detail">
        <div class="info">
          <a class="avatar" href="http://www.jianshu.com/u/3c8fe1455914">
            <img src="./Vue官方教程笔记（Vue 1.X） - 简书_files/a7744da1-649b-4db5-8e59-97e5b3d17de9.jpg" alt="96">
</a>          <a class="btn btn-success follow"><i class="iconfont ic-follow"></i><span>关注</span></a>
          <a class="title" href="http://www.jianshu.com/u/3c8fe1455914">Awey</a>
          
            <i class="iconfont ic-man"></i>
        <p>写了 46861 字，被 168 人关注，获得了 254 个喜欢</p></div>
          <div class="signature">SILENCE</div>
      </div>

      <div class="support-author"></div>

    <div class="meta-bottom">
      <div class="like"><div class="btn like-group"><div class="btn-like"><a><i class="iconfont ic-like"></i>喜欢</a></div> <div class="modal-wrap"><a>102</a></div></div> <!----></div>
      <div class="share-group">
        <a class="share-circle" data-action="weixin-share" data-toggle="tooltip" data-original-title="分享到微信">
          <i class="iconfont ic-wechat"></i>
        </a>
        <a class="share-circle" data-action="weibo-share" data-toggle="tooltip" href="javascript:void((function(s,d,e,r,l,p,t,z,c){var%20f=&#39;http://v.t.sina.com.cn/share/share.php?appkey=1881139527&#39;,u=z||d.location,p=[&#39;&amp;url=&#39;,e(u),&#39;&amp;title=&#39;,e(t||d.title),&#39;&amp;source=&#39;,e(r),&#39;&amp;sourceUrl=&#39;,e(l),&#39;&amp;content=&#39;,c||&#39;gb2312&#39;,&#39;&amp;pic=&#39;,e(p||&#39;&#39;)].join(&#39;&#39;);function%20a(){if(!window.open([f,p].join(&#39;&#39;),&#39;mb&#39;,[&#39;toolbar=0,status=0,resizable=1,width=440,height=430,left=&#39;,(s.width-440)/2,&#39;,top=&#39;,(s.height-430)/2].join(&#39;&#39;)))u.href=[f,p].join(&#39;&#39;);};if(/Firefox/.test(navigator.userAgent))setTimeout(a,0);else%20a();})(screen,document,encodeURIComponent,&#39;&#39;,&#39;&#39;,&#39;http://cwb.assets.jianshu.io/notes/images/5917355/weibo/image_34aaf3700d44.png&#39;, &#39;推荐 Awey 的文章《Vue官方教程笔记（Vue 1.X）》（ 分享自 @简书 ）&#39;,&#39;http://www.jianshu.com/p/c1a776c7a228?utm_campaign=maleskine&amp;utm_content=note&amp;utm_medium=reader_share&amp;utm_source=weibo&#39;,&#39;页面编码gb2312|utf-8默认gb2312&#39;));" data-original-title="分享到微博">
          <i class="iconfont ic-weibo"></i>
        </a>
          <a class="share-circle" data-toggle="tooltip" href="http://cwb.assets.jianshu.io/notes/images/5917355/weibo/image_34aaf3700d44.png" target="_blank" data-original-title="下载长微博图片">
            <i class="iconfont ic-picture"></i>
          </a>
        <a class="share-circle more-share" tabindex="0" data-toggle="popover" data-placement="top" data-html="true" data-trigger="focus" href="javascript:void(0);" data-content="
          &lt;ul class=&quot;share-list&quot;&gt;
            &lt;li&gt;&lt;a href=&quot;javascript:void(function(){var d=document,e=encodeURIComponent,r=&#39;http://sns.qzone.qq.com/cgi-bin/qzshare/cgi_qzshare_onekey?url=&#39;+e(&#39;http://www.jianshu.com/p/c1a776c7a228?utm_campaign=maleskine&amp;utm_content=note&amp;utm_medium=reader_share&amp;utm_source=qzone&#39;)+&#39;&amp;title=&#39;+e(&#39;推荐 Awey 的文章《Vue官方教程笔记（Vue 1.X）》&#39;),x=function(){if(!window.open(r,&#39;qzone&#39;,&#39;toolbar=0,resizable=1,scrollbars=yes,status=1,width=600,height=600&#39;))location.href=r};if(/Firefox/.test(navigator.userAgent)){setTimeout(x,0)}else{x()}})();&quot;&gt;&lt;i class=&quot;social-icon-sprite social-icon-zone&quot;&gt;&lt;/i&gt;&lt;span&gt;分享到QQ空间&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
            &lt;li&gt;&lt;a href=&quot;javascript:void(function(){var d=document,e=encodeURIComponent,r=&#39;https://twitter.com/share?url=&#39;+e(&#39;http://www.jianshu.com/p/c1a776c7a228?utm_campaign=maleskine&amp;utm_content=note&amp;utm_medium=reader_share&amp;utm_source=twitter&#39;)+&#39;&amp;text=&#39;+e(&#39;推荐 Awey 的文章《Vue官方教程笔记（Vue 1.X）》（ 分享自 @jianshucom ）&#39;)+&#39;&amp;related=&#39;+e(&#39;jianshucom&#39;),x=function(){if(!window.open(r,&#39;twitter&#39;,&#39;toolbar=0,resizable=1,scrollbars=yes,status=1,width=600,height=600&#39;))location.href=r};if(/Firefox/.test(navigator.userAgent)){setTimeout(x,0)}else{x()}})();&quot;&gt;&lt;i class=&quot;social-icon-sprite social-icon-twitter&quot;&gt;&lt;/i&gt;&lt;span&gt;分享到Twitter&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
            &lt;li&gt;&lt;a href=&quot;javascript:void(function(){var d=document,e=encodeURIComponent,r=&#39;https://www.facebook.com/dialog/share?app_id=483126645039390&amp;display=popup&amp;href=http://www.jianshu.com/p/c1a776c7a228?utm_campaign=maleskine&amp;utm_content=note&amp;utm_medium=reader_share&amp;utm_source=facebook&#39;,x=function(){if(!window.open(r,&#39;facebook&#39;,&#39;toolbar=0,resizable=1,scrollbars=yes,status=1,width=450,height=330&#39;))location.href=r};if(/Firefox/.test(navigator.userAgent)){setTimeout(x,0)}else{x()}})();&quot;&gt;&lt;i class=&quot;social-icon-sprite social-icon-facebook&quot;&gt;&lt;/i&gt;&lt;span&gt;分享到Facebook&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
            &lt;li&gt;&lt;a href=&quot;javascript:void(function(){var d=document,e=encodeURIComponent,r=&#39;https://plus.google.com/share?url=&#39;+e(&#39;http://www.jianshu.com/p/c1a776c7a228?utm_campaign=maleskine&amp;utm_content=note&amp;utm_medium=reader_share&amp;utm_source=google_plus&#39;),x=function(){if(!window.open(r,&#39;google_plus&#39;,&#39;toolbar=0,resizable=1,scrollbars=yes,status=1,width=450,height=330&#39;))location.href=r};if(/Firefox/.test(navigator.userAgent)){setTimeout(x,0)}else{x()}})();&quot;&gt;&lt;i class=&quot;social-icon-sprite social-icon-google&quot;&gt;&lt;/i&gt;&lt;span&gt;分享到Google+&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
            &lt;li&gt;&lt;a href=&quot;javascript:void(function(){var d=document,e=encodeURIComponent,s1=window.getSelection,s2=d.getSelection,s3=d.selection,s=s1?s1():s2?s2():s3?s3.createRange().text:&#39;&#39;,r=&#39;http://www.douban.com/recommend/?url=&#39;+e(&#39;http://www.jianshu.com/p/c1a776c7a228?utm_campaign=maleskine&amp;utm_content=note&amp;utm_medium=reader_share&amp;utm_source=douban&#39;)+&#39;&amp;title=&#39;+e(&#39;Vue官方教程笔记（Vue 1.X）&#39;)+&#39;&amp;sel=&#39;+e(s)+&#39;&amp;v=1&#39;,x=function(){if(!window.open(r,&#39;douban&#39;,&#39;toolbar=0,resizable=1,scrollbars=yes,status=1,width=450,height=330&#39;))location.href=r+&#39;&amp;r=1&#39;};if(/Firefox/.test(navigator.userAgent)){setTimeout(x,0)}else{x()}})()&quot;&gt;&lt;i class=&quot;social-icon-sprite social-icon-douban&quot;&gt;&lt;/i&gt;&lt;span&gt;分享到豆瓣&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
          &lt;/ul&gt;
        " data-original-title="" title="">更多分享</a>
      </div>
    </div>
    <div id="vue_comment"></div>
  </div>

  <div class="side-tool"><ul><li data-placement="left" data-toggle="tooltip" data-container="body" data-original-title="回到顶部" style=""><a class="function-button"><i class="iconfont ic-backtop"></i></a></li> <li data-placement="left" data-toggle="tooltip" data-container="body" data-original-title="将文章加入专题"><a class="js-submit-button"><i class="iconfont ic-addcollectionmodal"></i></a> <!----></li> <li data-placement="left" data-toggle="tooltip" data-container="body" data-original-title="收藏文章"><a class="function-button"><i class="iconfont ic-mark"></i></a></li> <li data-placement="left" data-toggle="tooltip" data-container="body" data-original-title="分享文章"><a tabindex="0" role="button" data-toggle="popover" data-placement="left" data-html="true" data-trigger="focus" href="javascript:void(0);" data-content="&lt;ul class=&#39;share-list&#39;&gt;
                &lt;li&gt;&lt;a class=&quot;weixin-share&quot;&gt;&lt;i class=&quot;social-icon-sprite social-icon-weixin&quot;&gt;&lt;/i&gt;&lt;span&gt;分享到微信&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
                &lt;li&gt;&lt;a href=&quot;javascript:void((function(s,d,e,r,l,p,t,z,c){var%20f=&#39;http://v.t.sina.com.cn/share/share.php?appkey=1881139527&#39;,u=z||d.location,p=[&#39;&amp;url=&#39;,e(u),&#39;&amp;title=&#39;,e(t||d.title),&#39;&amp;source=&#39;,e(r),&#39;&amp;sourceUrl=&#39;,e(l),&#39;&amp;content=&#39;,c||&#39;gb2312&#39;,&#39;&amp;pic=&#39;,e(p||&#39;&#39;)].join(&#39;&#39;);function%20a(){if(!window.open([f,p].join(&#39;&#39;),&#39;mb&#39;,[&#39;toolbar=0,status=0,resizable=1,width=440,height=430,left=&#39;,(s.width-440)/2,&#39;,top=&#39;,(s.height-430)/2].join(&#39;&#39;)))u.href=[f,p].join(&#39;&#39;);};if(/Firefox/.test(navigator.userAgent))setTimeout(a,0);else%20a();})(screen,document,encodeURIComponent,&#39;&#39;,&#39;&#39;,&#39;http://cwb.assets.jianshu.io/notes/images/5917355/weibo/image_34aaf3700d44.png&#39;, &#39;推荐 Awey 的文章《Vue官方教程笔记（Vue 1.X）》（ 分享自 @简书 ）&#39;,&#39;http://www.jianshu.com/p/c1a776c7a228?utm_campaign=maleskine&amp;utm_content=note&amp;utm_medium=reader_share&amp;utm_source=weibo&#39;,&#39;页面编码gb2312|utf-8默认gb2312&#39;));&quot;&gt;&lt;i class=&#39;social-icon-sprite social-icon-weibo&#39;&gt;&lt;/i&gt;&lt;span&gt;分享到微博&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
                &lt;li&gt;&lt;a href=&quot;http://cwb.assets.jianshu.io/notes/images/5917355/weibo/image_34aaf3700d44.png&quot; target=&quot;_blank&quot;&gt;&lt;i class=&quot;social-icon-sprite social-icon-picture&quot;&gt;&lt;/i&gt;&lt;span&gt;下载长微博图片&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
                &lt;li&gt;&lt;a href=&quot;javascript:void(function(){var d=document,e=encodeURIComponent,r=&#39;http://sns.qzone.qq.com/cgi-bin/qzshare/cgi_qzshare_onekey?url=&#39;+e(&#39;http://www.jianshu.com/p/c1a776c7a228?utm_campaign=maleskine&amp;utm_content=note&amp;utm_medium=reader_share&amp;utm_source=qzone&#39;)+&#39;&amp;title=&#39;+e(&#39;推荐 Awey 的文章《Vue官方教程笔记（Vue 1.X）》&#39;),x=function(){if(!window.open(r,&#39;qzone&#39;,&#39;toolbar=0,resizable=1,scrollbars=yes,status=1,width=600,height=600&#39;))location.href=r};if(/Firefox/.test(navigator.userAgent)){setTimeout(x,0)}else{x()}})();&quot;&gt;&lt;i class=&#39;social-icon-sprite social-icon-zone&#39;&gt;&lt;/i&gt;&lt;span&gt;分享到QQ空间&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
                &lt;li&gt;&lt;a href=&quot;javascript:void(function(){var d=document,e=encodeURIComponent,r=&#39;https://twitter.com/share?url=&#39;+e(&#39;http://www.jianshu.com/p/c1a776c7a228?utm_campaign=maleskine&amp;utm_content=note&amp;utm_medium=reader_share&amp;utm_source=twitter&#39;)+&#39;&amp;text=&#39;+e(&#39;推荐 Awey 的文章《Vue官方教程笔记（Vue 1.X）》（ 分享自 @jianshucom ）&#39;)+&#39;&amp;related=&#39;+e(&#39;jianshucom&#39;),x=function(){if(!window.open(r,&#39;twitter&#39;,&#39;toolbar=0,resizable=1,scrollbars=yes,status=1,width=600,height=600&#39;))location.href=r};if(/Firefox/.test(navigator.userAgent)){setTimeout(x,0)}else{x()}})();&quot;&gt;&lt;i class=&#39;social-icon-sprite social-icon-twitter&#39;&gt;&lt;/i&gt;&lt;span&gt;分享到Twitter&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
                &lt;li&gt;&lt;a href=&quot;javascript:void(function(){var d=document,e=encodeURIComponent,r=&#39;https://www.facebook.com/dialog/share?app_id=483126645039390&amp;display=popup&amp;href=http://www.jianshu.com/p/c1a776c7a228?utm_campaign=maleskine&amp;utm_content=note&amp;utm_medium=reader_share&amp;utm_source=facebook&#39;,x=function(){if(!window.open(r,&#39;facebook&#39;,&#39;toolbar=0,resizable=1,scrollbars=yes,status=1,width=450,height=330&#39;))location.href=r};if(/Firefox/.test(navigator.userAgent)){setTimeout(x,0)}else{x()}})();&quot;&gt;&lt;i class=&#39;social-icon-sprite social-icon-facebook&#39;&gt;&lt;/i&gt;&lt;span&gt;分享到Facebook&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
                &lt;li&gt;&lt;a href=&quot;javascript:void(function(){var d=document,e=encodeURIComponent,r=&#39;https://plus.google.com/share?url=&#39;+e(&#39;http://www.jianshu.com/p/c1a776c7a228?utm_campaign=maleskine&amp;utm_content=note&amp;utm_medium=reader_share&amp;utm_source=google_plus&#39;),x=function(){if(!window.open(r,&#39;google_plus&#39;,&#39;toolbar=0,resizable=1,scrollbars=yes,status=1,width=450,height=330&#39;))location.href=r};if(/Firefox/.test(navigator.userAgent)){setTimeout(x,0)}else{x()}})();&quot;&gt;&lt;i class=&#39;social-icon-sprite social-icon-google&#39;&gt;&lt;/i&gt;&lt;span&gt;分享到Google+&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
                &lt;li&gt;&lt;a href=&quot;javascript:void(function(){var d=document,e=encodeURIComponent,s1=window.getSelection,s2=d.getSelection,s3=d.selection,s=s1?s1():s2?s2():s3?s3.createRange().text:&#39;&#39;,r=&#39;http://www.douban.com/recommend/?url=&#39;+e(&#39;http://www.jianshu.com/p/c1a776c7a228?utm_campaign=maleskine&amp;utm_content=note&amp;utm_medium=reader_share&amp;utm_source=douban&#39;)+&#39;&amp;title=&#39;+e(&#39;Vue官方教程笔记（Vue 1.X）&#39;)+&#39;&amp;sel=&#39;+e(s)+&#39;&amp;v=1&#39;,x=function(){if(!window.open(r,&#39;douban&#39;,&#39;toolbar=0,resizable=1,scrollbars=yes,status=1,width=450,height=330&#39;))location.href=r+&#39;&amp;r=1&#39;};if(/Firefox/.test(navigator.userAgent)){setTimeout(x,0)}else{x()}})()&quot;&gt;&lt;i class=&#39;social-icon-sprite social-icon-douban&#39;&gt;&lt;/i&gt;&lt;span&gt;分享到豆瓣&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
              &lt;/ul&gt;" data-original-title="" title="" class="function-button"><i class="iconfont ic-share"></i></a> <!----></li> <!----></ul></div>
</div>
<div class="note-bottom">
  <div><div class="main"><div class="title">被以下专题收入，发现更多相似内容</div> <!----> <div class="include-collection"><div class="modal-wrap add-collection-wrap"><a class="add-collection"><i class="iconfont ic-follow"></i>收入我的专题</a></div> <a href="http://www.jianshu.com/c/22c0d54ed228?utm_source=desktop&amp;utm_medium=notes-included-collection" target="_blank" class="item"><img src="./Vue官方教程笔记（Vue 1.X） - 简书_files/j2MRZv.png"><div class="name">Vue.js开发技巧</div></a> <!----></div></div> <!----> <!----></div>
  <div data-vcomp="recommended-notes" data-note-id="5917355"></div>
</div>

    <script type="application/json" data-name="page-data">{"user_signed_in":true,"locale":"zh-CN","os":"windows","read_mode":"day","read_font":"font2","current_user":{"id":874603,"nickname":"leiyantianji","slug":"aae7e00037b6","avatar":"http://upload.jianshu.io/users/upload_avatars/874603/b7b003ddd980.jpg","unread_counts":{"requests":0,"total":0},"has_editable_collection":true},"note_show":{"is_author":false,"is_following_author":false,"is_liked_note":false,"follow_state":0,"uuid":"fa939e8b-947f-49e1-b0cd-0594e94489d8"},"note":{"id":5917355,"slug":"c1a776c7a228","user_id":3094907,"notebook_id":6409590,"commentable":true,"likes_count":102,"views_count":4210,"public_wordage":9633,"comments_count":3,"total_rewards_count":0,"is_author":false,"author":{"nickname":"Awey","total_wordage":46861,"followers_count":168,"total_likes_count":254}}}</script>
    
    <script src="./Vue官方教程笔记（Vue 1.X） - 简书_files/babel-polyfill-676833c6a4d68573b4c3.js.下载" crossorigin="anonymous"></script>
    <script src="./Vue官方教程笔记（Vue 1.X） - 简书_files/web-base-25e18e118d9b6a91e38c.js.下载" crossorigin="anonymous"></script>
<script src="./Vue官方教程笔记（Vue 1.X） - 简书_files/web-06a150210213bf3f6bb0.js.下载" crossorigin="anonymous"></script>
    
    <script src="./Vue官方教程笔记（Vue 1.X） - 简书_files/entry-6a35bef065d2ef07c858.js.下载" crossorigin="anonymous"></script>
    <script>
  (function(){
      var bp = document.createElement('script');
      var curProtocol = window.location.protocol.split(':')[0];
      if (curProtocol === 'https') {
          bp.src = 'https://zz.bdstatic.com/linksubmit/push.js';
      }
      else {
          bp.src = 'http://push.zhanzhang.baidu.com/push.js';
      }
      var s = document.getElementsByTagName("script")[0];
      s.parentNode.insertBefore(bp, s);
  })();
</script>

  

<!----><!----><!----></body></html>